xref: /openbmc/linux/net/netfilter/xt_TPROXY.c (revision ff67e4e4)
1e8439270SKOVACS Krisztian /*
2e8439270SKOVACS Krisztian  * Transparent proxy support for Linux/iptables
3e8439270SKOVACS Krisztian  *
4e8439270SKOVACS Krisztian  * Copyright (c) 2006-2007 BalaBit IT Ltd.
5e8439270SKOVACS Krisztian  * Author: Balazs Scheidler, Krisztian Kovacs
6e8439270SKOVACS Krisztian  *
7e8439270SKOVACS Krisztian  * This program is free software; you can redistribute it and/or modify
8e8439270SKOVACS Krisztian  * it under the terms of the GNU General Public License version 2 as
9e8439270SKOVACS Krisztian  * published by the Free Software Foundation.
10e8439270SKOVACS Krisztian  *
11e8439270SKOVACS Krisztian  */
12ff67e4e4SJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13e8439270SKOVACS Krisztian #include <linux/module.h>
14e8439270SKOVACS Krisztian #include <linux/skbuff.h>
15e8439270SKOVACS Krisztian #include <linux/ip.h>
16e8439270SKOVACS Krisztian #include <net/checksum.h>
17e8439270SKOVACS Krisztian #include <net/udp.h>
18e8439270SKOVACS Krisztian #include <net/inet_sock.h>
19e8439270SKOVACS Krisztian 
20e8439270SKOVACS Krisztian #include <linux/netfilter/x_tables.h>
21e8439270SKOVACS Krisztian #include <linux/netfilter_ipv4/ip_tables.h>
22e8439270SKOVACS Krisztian #include <linux/netfilter/xt_TPROXY.h>
23e8439270SKOVACS Krisztian 
24e8439270SKOVACS Krisztian #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
25e8439270SKOVACS Krisztian #include <net/netfilter/nf_tproxy_core.h>
26e8439270SKOVACS Krisztian 
27e8439270SKOVACS Krisztian static unsigned int
287eb35586SJan Engelhardt tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par)
29e8439270SKOVACS Krisztian {
30e8439270SKOVACS Krisztian 	const struct iphdr *iph = ip_hdr(skb);
317eb35586SJan Engelhardt 	const struct xt_tproxy_target_info *tgi = par->targinfo;
32e8439270SKOVACS Krisztian 	struct udphdr _hdr, *hp;
33e8439270SKOVACS Krisztian 	struct sock *sk;
34e8439270SKOVACS Krisztian 
35e8439270SKOVACS Krisztian 	hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
36e8439270SKOVACS Krisztian 	if (hp == NULL)
37e8439270SKOVACS Krisztian 		return NF_DROP;
38e8439270SKOVACS Krisztian 
39e8439270SKOVACS Krisztian 	sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
40e8439270SKOVACS Krisztian 				   iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
41e8439270SKOVACS Krisztian 				   hp->source, tgi->lport ? tgi->lport : hp->dest,
427eb35586SJan Engelhardt 				   par->in, true);
43e8439270SKOVACS Krisztian 
44e8439270SKOVACS Krisztian 	/* NOTE: assign_sock consumes our sk reference */
45e8439270SKOVACS Krisztian 	if (sk && nf_tproxy_assign_sock(skb, sk)) {
46e8439270SKOVACS Krisztian 		/* This should be in a separate target, but we don't do multiple
47e8439270SKOVACS Krisztian 		   targets on the same rule yet */
48e8439270SKOVACS Krisztian 		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
49e8439270SKOVACS Krisztian 
50e8439270SKOVACS Krisztian 		pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n",
51e8439270SKOVACS Krisztian 			 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
52e8439270SKOVACS Krisztian 			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
53e8439270SKOVACS Krisztian 		return NF_ACCEPT;
54e8439270SKOVACS Krisztian 	}
55e8439270SKOVACS Krisztian 
56e8439270SKOVACS Krisztian 	pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark: %x\n",
57e8439270SKOVACS Krisztian 		 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
58e8439270SKOVACS Krisztian 		 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
59e8439270SKOVACS Krisztian 	return NF_DROP;
60e8439270SKOVACS Krisztian }
61e8439270SKOVACS Krisztian 
62af5d6dc2SJan Engelhardt static bool tproxy_tg_check(const struct xt_tgchk_param *par)
63e8439270SKOVACS Krisztian {
64af5d6dc2SJan Engelhardt 	const struct ipt_ip *i = par->entryinfo;
65e8439270SKOVACS Krisztian 
66e8439270SKOVACS Krisztian 	if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
67e8439270SKOVACS Krisztian 	    && !(i->invflags & IPT_INV_PROTO))
68e8439270SKOVACS Krisztian 		return true;
69e8439270SKOVACS Krisztian 
70ff67e4e4SJan Engelhardt 	pr_info("Can be used only in combination with "
71e8439270SKOVACS Krisztian 		"either -p tcp or -p udp\n");
72e8439270SKOVACS Krisztian 	return false;
73e8439270SKOVACS Krisztian }
74e8439270SKOVACS Krisztian 
75e8439270SKOVACS Krisztian static struct xt_target tproxy_tg_reg __read_mostly = {
76e8439270SKOVACS Krisztian 	.name		= "TPROXY",
77e8439270SKOVACS Krisztian 	.family		= AF_INET,
78e8439270SKOVACS Krisztian 	.table		= "mangle",
79e8439270SKOVACS Krisztian 	.target		= tproxy_tg,
80e8439270SKOVACS Krisztian 	.targetsize	= sizeof(struct xt_tproxy_target_info),
81e8439270SKOVACS Krisztian 	.checkentry	= tproxy_tg_check,
82e8439270SKOVACS Krisztian 	.hooks		= 1 << NF_INET_PRE_ROUTING,
83e8439270SKOVACS Krisztian 	.me		= THIS_MODULE,
84e8439270SKOVACS Krisztian };
85e8439270SKOVACS Krisztian 
86e8439270SKOVACS Krisztian static int __init tproxy_tg_init(void)
87e8439270SKOVACS Krisztian {
88e8439270SKOVACS Krisztian 	nf_defrag_ipv4_enable();
89e8439270SKOVACS Krisztian 	return xt_register_target(&tproxy_tg_reg);
90e8439270SKOVACS Krisztian }
91e8439270SKOVACS Krisztian 
92e8439270SKOVACS Krisztian static void __exit tproxy_tg_exit(void)
93e8439270SKOVACS Krisztian {
94e8439270SKOVACS Krisztian 	xt_unregister_target(&tproxy_tg_reg);
95e8439270SKOVACS Krisztian }
96e8439270SKOVACS Krisztian 
97e8439270SKOVACS Krisztian module_init(tproxy_tg_init);
98e8439270SKOVACS Krisztian module_exit(tproxy_tg_exit);
99e8439270SKOVACS Krisztian MODULE_LICENSE("GPL");
100e8439270SKOVACS Krisztian MODULE_AUTHOR("Krisztian Kovacs");
101e8439270SKOVACS Krisztian MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
102e8439270SKOVACS Krisztian MODULE_ALIAS("ipt_TPROXY");
103