PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/net/netfilter/xt_TPROXY.c

https://gitlab.com/deadnem/Singularity
C | 432 lines | 300 code | 60 blank | 72 comment | 53 complexity | 4e2cb41565e93e3ccdf4630549ea2eee MD5 | raw file
  1. /*
  2. * Transparent proxy support for Linux/iptables
  3. *
  4. * Copyright (c) 2006-2010 BalaBit IT Ltd.
  5. * Author: Balazs Scheidler, Krisztian Kovacs
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. */
  12. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13. #include <linux/module.h>
  14. #include <linux/skbuff.h>
  15. #include <linux/ip.h>
  16. #include <net/checksum.h>
  17. #include <net/udp.h>
  18. #include <net/inet_sock.h>
  19. #include <linux/inetdevice.h>
  20. #include <linux/netfilter/x_tables.h>
  21. #include <linux/netfilter_ipv4/ip_tables.h>
  22. #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
  23. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  24. #define XT_TPROXY_HAVE_IPV6 1
  25. #include <net/if_inet6.h>
  26. #include <net/addrconf.h>
  27. #include <linux/netfilter_ipv6/ip6_tables.h>
  28. #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  29. #endif
  30. #include <net/netfilter/nf_tproxy_core.h>
  31. #include <linux/netfilter/xt_TPROXY.h>
  32. static bool tproxy_sk_is_transparent(struct sock *sk)
  33. {
  34. if (sk->sk_state != TCP_TIME_WAIT) {
  35. if (inet_sk(sk)->transparent)
  36. return true;
  37. sock_put(sk);
  38. } else {
  39. if (inet_twsk(sk)->tw_transparent)
  40. return true;
  41. inet_twsk_put(inet_twsk(sk));
  42. }
  43. return false;
  44. }
  45. static inline __be32
  46. tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
  47. {
  48. struct in_device *indev;
  49. __be32 laddr;
  50. if (user_laddr)
  51. return user_laddr;
  52. laddr = 0;
  53. rcu_read_lock();
  54. indev = __in_dev_get_rcu(skb->dev);
  55. for_primary_ifa(indev) {
  56. laddr = ifa->ifa_local;
  57. break;
  58. } endfor_ifa(indev);
  59. rcu_read_unlock();
  60. return laddr ? laddr : daddr;
  61. }
  62. /**
  63. * tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections
  64. * @skb: The skb being processed.
  65. * @laddr: IPv4 address to redirect to or zero.
  66. * @lport: TCP port to redirect to or zero.
  67. * @sk: The TIME_WAIT TCP socket found by the lookup.
  68. *
  69. * We have to handle SYN packets arriving to TIME_WAIT sockets
  70. * differently: instead of reopening the connection we should rather
  71. * redirect the new connection to the proxy if there's a listener
  72. * socket present.
  73. *
  74. * tproxy_handle_time_wait4() consumes the socket reference passed in.
  75. *
  76. * Returns the listener socket if there's one, the TIME_WAIT socket if
  77. * no such listener is found, or NULL if the TCP header is incomplete.
  78. */
  79. static struct sock *
  80. tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
  81. struct sock *sk)
  82. {
  83. const struct iphdr *iph = ip_hdr(skb);
  84. struct tcphdr _hdr, *hp;
  85. hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
  86. if (hp == NULL) {
  87. inet_twsk_put(inet_twsk(sk));
  88. return NULL;
  89. }
  90. if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
  91. /* SYN to a TIME_WAIT socket, we'd rather redirect it
  92. * to a listener socket if there's one */
  93. struct sock *sk2;
  94. sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
  95. iph->saddr, laddr ? laddr : iph->daddr,
  96. hp->source, lport ? lport : hp->dest,
  97. skb->dev, NFT_LOOKUP_LISTENER);
  98. if (sk2) {
  99. inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
  100. inet_twsk_put(inet_twsk(sk));
  101. sk = sk2;
  102. }
  103. }
  104. return sk;
  105. }
  106. static unsigned int
  107. tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
  108. u_int32_t mark_mask, u_int32_t mark_value)
  109. {
  110. const struct iphdr *iph = ip_hdr(skb);
  111. struct udphdr _hdr, *hp;
  112. struct sock *sk;
  113. hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
  114. if (hp == NULL)
  115. return NF_DROP;
  116. /* check if there's an ongoing connection on the packet
  117. * addresses, this happens if the redirect already happened
  118. * and the current packet belongs to an already established
  119. * connection */
  120. sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
  121. iph->saddr, iph->daddr,
  122. hp->source, hp->dest,
  123. skb->dev, NFT_LOOKUP_ESTABLISHED);
  124. laddr = tproxy_laddr4(skb, laddr, iph->daddr);
  125. if (!lport)
  126. lport = hp->dest;
  127. /* UDP has no TCP_TIME_WAIT state, so we never enter here */
  128. if (sk && sk->sk_state == TCP_TIME_WAIT)
  129. /* reopening a TIME_WAIT connection needs special handling */
  130. sk = tproxy_handle_time_wait4(skb, laddr, lport, sk);
  131. else if (!sk)
  132. /* no, there's no established connection, check if
  133. * there's a listener on the redirected addr/port */
  134. sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
  135. iph->saddr, laddr,
  136. hp->source, lport,
  137. skb->dev, NFT_LOOKUP_LISTENER);
  138. /* NOTE: assign_sock consumes our sk reference */
  139. if (sk && tproxy_sk_is_transparent(sk)) {
  140. /* This should be in a separate target, but we don't do multiple
  141. targets on the same rule yet */
  142. skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
  143. pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
  144. iph->protocol, &iph->daddr, ntohs(hp->dest),
  145. &laddr, ntohs(lport), skb->mark);
  146. nf_tproxy_assign_sock(skb, sk);
  147. return NF_ACCEPT;
  148. }
  149. pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
  150. iph->protocol, &iph->saddr, ntohs(hp->source),
  151. &iph->daddr, ntohs(hp->dest), skb->mark);
  152. return NF_DROP;
  153. }
  154. static unsigned int
  155. tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par)
  156. {
  157. const struct xt_tproxy_target_info *tgi = par->targinfo;
  158. return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value);
  159. }
  160. static unsigned int
  161. tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
  162. {
  163. const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
  164. return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
  165. }
  166. #ifdef XT_TPROXY_HAVE_IPV6
  167. static inline const struct in6_addr *
  168. tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
  169. const struct in6_addr *daddr)
  170. {
  171. struct inet6_dev *indev;
  172. struct inet6_ifaddr *ifa;
  173. struct in6_addr *laddr;
  174. if (!ipv6_addr_any(user_laddr))
  175. return user_laddr;
  176. laddr = NULL;
  177. rcu_read_lock();
  178. indev = __in6_dev_get(skb->dev);
  179. if (indev)
  180. list_for_each_entry(ifa, &indev->addr_list, if_list) {
  181. if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
  182. continue;
  183. laddr = &ifa->addr;
  184. break;
  185. }
  186. rcu_read_unlock();
  187. return laddr ? laddr : daddr;
  188. }
  189. /**
  190. * tproxy_handle_time_wait6 - handle IPv6 TCP TIME_WAIT reopen redirections
  191. * @skb: The skb being processed.
  192. * @tproto: Transport protocol.
  193. * @thoff: Transport protocol header offset.
  194. * @par: Iptables target parameters.
  195. * @sk: The TIME_WAIT TCP socket found by the lookup.
  196. *
  197. * We have to handle SYN packets arriving to TIME_WAIT sockets
  198. * differently: instead of reopening the connection we should rather
  199. * redirect the new connection to the proxy if there's a listener
  200. * socket present.
  201. *
  202. * tproxy_handle_time_wait6() consumes the socket reference passed in.
  203. *
  204. * Returns the listener socket if there's one, the TIME_WAIT socket if
  205. * no such listener is found, or NULL if the TCP header is incomplete.
  206. */
  207. static struct sock *
  208. tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
  209. const struct xt_action_param *par,
  210. struct sock *sk)
  211. {
  212. const struct ipv6hdr *iph = ipv6_hdr(skb);
  213. struct tcphdr _hdr, *hp;
  214. const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
  215. hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
  216. if (hp == NULL) {
  217. inet_twsk_put(inet_twsk(sk));
  218. return NULL;
  219. }
  220. if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
  221. /* SYN to a TIME_WAIT socket, we'd rather redirect it
  222. * to a listener socket if there's one */
  223. struct sock *sk2;
  224. sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
  225. &iph->saddr,
  226. tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
  227. hp->source,
  228. tgi->lport ? tgi->lport : hp->dest,
  229. skb->dev, NFT_LOOKUP_LISTENER);
  230. if (sk2) {
  231. inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
  232. inet_twsk_put(inet_twsk(sk));
  233. sk = sk2;
  234. }
  235. }
  236. return sk;
  237. }
  238. static unsigned int
  239. tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
  240. {
  241. const struct ipv6hdr *iph = ipv6_hdr(skb);
  242. const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
  243. struct udphdr _hdr, *hp;
  244. struct sock *sk;
  245. const struct in6_addr *laddr;
  246. __be16 lport;
  247. int thoff = 0;
  248. int tproto;
  249. tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
  250. if (tproto < 0) {
  251. pr_debug("unable to find transport header in IPv6 packet, dropping\n");
  252. return NF_DROP;
  253. }
  254. hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
  255. if (hp == NULL) {
  256. pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
  257. return NF_DROP;
  258. }
  259. /* check if there's an ongoing connection on the packet
  260. * addresses, this happens if the redirect already happened
  261. * and the current packet belongs to an already established
  262. * connection */
  263. sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
  264. &iph->saddr, &iph->daddr,
  265. hp->source, hp->dest,
  266. par->in, NFT_LOOKUP_ESTABLISHED);
  267. laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
  268. lport = tgi->lport ? tgi->lport : hp->dest;
  269. /* UDP has no TCP_TIME_WAIT state, so we never enter here */
  270. if (sk && sk->sk_state == TCP_TIME_WAIT)
  271. /* reopening a TIME_WAIT connection needs special handling */
  272. sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk);
  273. else if (!sk)
  274. /* no there's no established connection, check if
  275. * there's a listener on the redirected addr/port */
  276. sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
  277. &iph->saddr, laddr,
  278. hp->source, lport,
  279. par->in, NFT_LOOKUP_LISTENER);
  280. /* NOTE: assign_sock consumes our sk reference */
  281. if (sk && tproxy_sk_is_transparent(sk)) {
  282. /* This should be in a separate target, but we don't do multiple
  283. targets on the same rule yet */
  284. skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
  285. pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
  286. tproto, &iph->saddr, ntohs(hp->source),
  287. laddr, ntohs(lport), skb->mark);
  288. nf_tproxy_assign_sock(skb, sk);
  289. return NF_ACCEPT;
  290. }
  291. pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
  292. tproto, &iph->saddr, ntohs(hp->source),
  293. &iph->daddr, ntohs(hp->dest), skb->mark);
  294. return NF_DROP;
  295. }
  296. static int tproxy_tg6_check(const struct xt_tgchk_param *par)
  297. {
  298. const struct ip6t_ip6 *i = par->entryinfo;
  299. if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
  300. && !(i->flags & IP6T_INV_PROTO))
  301. return 0;
  302. pr_info("Can be used only in combination with "
  303. "either -p tcp or -p udp\n");
  304. return -EINVAL;
  305. }
  306. #endif
  307. static int tproxy_tg4_check(const struct xt_tgchk_param *par)
  308. {
  309. const struct ipt_ip *i = par->entryinfo;
  310. if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
  311. && !(i->invflags & IPT_INV_PROTO))
  312. return 0;
  313. pr_info("Can be used only in combination with "
  314. "either -p tcp or -p udp\n");
  315. return -EINVAL;
  316. }
  317. static struct xt_target tproxy_tg_reg[] __read_mostly = {
  318. {
  319. .name = "TPROXY",
  320. .family = NFPROTO_IPV4,
  321. .table = "mangle",
  322. .target = tproxy_tg4_v0,
  323. .revision = 0,
  324. .targetsize = sizeof(struct xt_tproxy_target_info),
  325. .checkentry = tproxy_tg4_check,
  326. .hooks = 1 << NF_INET_PRE_ROUTING,
  327. .me = THIS_MODULE,
  328. },
  329. {
  330. .name = "TPROXY",
  331. .family = NFPROTO_IPV4,
  332. .table = "mangle",
  333. .target = tproxy_tg4_v1,
  334. .revision = 1,
  335. .targetsize = sizeof(struct xt_tproxy_target_info_v1),
  336. .checkentry = tproxy_tg4_check,
  337. .hooks = 1 << NF_INET_PRE_ROUTING,
  338. .me = THIS_MODULE,
  339. },
  340. #ifdef XT_TPROXY_HAVE_IPV6
  341. {
  342. .name = "TPROXY",
  343. .family = NFPROTO_IPV6,
  344. .table = "mangle",
  345. .target = tproxy_tg6_v1,
  346. .revision = 1,
  347. .targetsize = sizeof(struct xt_tproxy_target_info_v1),
  348. .checkentry = tproxy_tg6_check,
  349. .hooks = 1 << NF_INET_PRE_ROUTING,
  350. .me = THIS_MODULE,
  351. },
  352. #endif
  353. };
  354. static int __init tproxy_tg_init(void)
  355. {
  356. nf_defrag_ipv4_enable();
  357. #ifdef XT_TPROXY_HAVE_IPV6
  358. nf_defrag_ipv6_enable();
  359. #endif
  360. return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
  361. }
  362. static void __exit tproxy_tg_exit(void)
  363. {
  364. xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
  365. }
  366. module_init(tproxy_tg_init);
  367. module_exit(tproxy_tg_exit);
  368. MODULE_LICENSE("GPL");
  369. MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs");
  370. MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
  371. MODULE_ALIAS("ipt_TPROXY");
  372. MODULE_ALIAS("ip6t_TPROXY");