116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy/* Amanda extension for TCP NAT alteration.
216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * based on a copy of HW's ip_nat_irc.c as well as other modules
4f229f6ce481ceb33a966311722b8ef0cb6c25de7Patrick McHardy * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy *
616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * This program is free software; you can redistribute it and/or
716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * modify it under the terms of the GNU General Public License
816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * as published by the Free Software Foundation; either version
916958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy * 2 of the License, or (at your option) any later version.
1016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy */
1116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
1216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <linux/kernel.h>
1316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <linux/module.h>
1416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <linux/skbuff.h>
1516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <linux/udp.h>
1616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
1716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <net/netfilter/nf_conntrack_helper.h>
1816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <net/netfilter/nf_conntrack_expect.h>
191afc56794e03229fa53cfa3c5012704d226e1decPablo Neira Ayuso#include <net/netfilter/nf_nat_helper.h>
2016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy#include <linux/netfilter/nf_conntrack_amanda.h>
2116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
2216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardyMODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
2316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardyMODULE_DESCRIPTION("Amanda NAT helper");
2416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardyMODULE_LICENSE("GPL");
2516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardyMODULE_ALIAS("ip_nat_amanda");
2616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
273db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xustatic unsigned int help(struct sk_buff *skb,
2816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy			 enum ip_conntrack_info ctinfo,
29051966c0c644a1c96092d4206e00704ade813c9aPatrick McHardy			 unsigned int protoff,
3016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy			 unsigned int matchoff,
3116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy			 unsigned int matchlen,
3216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy			 struct nf_conntrack_expect *exp)
3316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy{
3416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	char buffer[sizeof("65535")];
3516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	u_int16_t port;
3616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	unsigned int ret;
3716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
3816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	/* Connection comes from client. */
3916958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
4016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	exp->dir = IP_CT_DIR_ORIGINAL;
4116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
4216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	/* When you see the packet, we need to NAT it the same as the
4316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	 * this one (ie. same IP: it will be TCP and master is UDP). */
4416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	exp->expectfn = nf_nat_follow_master;
4516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
4616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	/* Try to get same port: if not, try to change it. */
4716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
48ab0cba25128e1435a59b1ec4ae0c7505548fed87Eric Dumazet		int res;
495b92b61f3891517d18d0573ad2c939c81b59ecfePablo Neira Ayuso
5016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy		exp->tuple.dst.u.tcp.port = htons(port);
51ab0cba25128e1435a59b1ec4ae0c7505548fed87Eric Dumazet		res = nf_ct_expect_related(exp);
52ab0cba25128e1435a59b1ec4ae0c7505548fed87Eric Dumazet		if (res == 0)
535b92b61f3891517d18d0573ad2c939c81b59ecfePablo Neira Ayuso			break;
54ab0cba25128e1435a59b1ec4ae0c7505548fed87Eric Dumazet		else if (res != -EBUSY) {
555b92b61f3891517d18d0573ad2c939c81b59ecfePablo Neira Ayuso			port = 0;
5616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy			break;
575b92b61f3891517d18d0573ad2c939c81b59ecfePablo Neira Ayuso		}
5816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	}
5916958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
60b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso	if (port == 0) {
61b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso		nf_ct_helper_log(skb, exp->master, "all ports in use");
6216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy		return NF_DROP;
63b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso	}
6416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
6516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	sprintf(buffer, "%u", port);
663db05fea51cdb162cfa8f69e9cfb9e228919d2a9Herbert Xu	ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
67051966c0c644a1c96092d4206e00704ade813c9aPatrick McHardy				       protoff, matchoff, matchlen,
6816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy				       buffer, strlen(buffer));
69b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso	if (ret != NF_ACCEPT) {
70b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso		nf_ct_helper_log(skb, exp->master, "cannot mangle packet");
716823645d608541c2c69e8a99454936e058c294e0Patrick McHardy		nf_ct_unexpect_related(exp);
72b20ab9cc63ca4605aec154cf54faa8455749f3f6Pablo Neira Ayuso	}
7316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	return ret;
7416958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy}
7516958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
7616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardystatic void __exit nf_nat_amanda_fini(void)
7716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy{
78a9b3cd7f323b2e57593e7215362a7b02fc933e3aStephen Hemminger	RCU_INIT_POINTER(nf_nat_amanda_hook, NULL);
7916958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	synchronize_rcu();
8016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy}
8116958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
8216958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardystatic int __init nf_nat_amanda_init(void)
8316958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy{
84d1332e0ab84479d941de5cf4a69c71dfd385a25ePatrick McHardy	BUG_ON(nf_nat_amanda_hook != NULL);
85a9b3cd7f323b2e57593e7215362a7b02fc933e3aStephen Hemminger	RCU_INIT_POINTER(nf_nat_amanda_hook, help);
8616958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy	return 0;
8716958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy}
8816958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardy
8916958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardymodule_init(nf_nat_amanda_init);
9016958900578b94585c2ab9a2d20d837b4d5e3ba6Patrick McHardymodule_exit(nf_nat_amanda_fini);
91