1 /* Amanda extension for TCP NAT alteration. 2 * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca> 3 * based on a copy of HW's ip_nat_irc.c as well as other modules 4 * (C) 2006-2012 Patrick McHardy <kaber@trash.net> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/skbuff.h> 15 #include <linux/udp.h> 16 17 #include <net/netfilter/nf_conntrack_helper.h> 18 #include <net/netfilter/nf_conntrack_expect.h> 19 #include <net/netfilter/nf_nat_helper.h> 20 #include <linux/netfilter/nf_conntrack_amanda.h> 21 22 MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); 23 MODULE_DESCRIPTION("Amanda NAT helper"); 24 MODULE_LICENSE("GPL"); 25 MODULE_ALIAS("ip_nat_amanda"); 26 27 static unsigned int help(struct sk_buff *skb, 28 enum ip_conntrack_info ctinfo, 29 unsigned int protoff, 30 unsigned int matchoff, 31 unsigned int matchlen, 32 struct nf_conntrack_expect *exp) 33 { 34 char buffer[sizeof("65535")]; 35 u_int16_t port; 36 37 /* Connection comes from client. */ 38 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; 39 exp->dir = IP_CT_DIR_ORIGINAL; 40 41 /* When you see the packet, we need to NAT it the same as the 42 * this one (ie. same IP: it will be TCP and master is UDP). */ 43 exp->expectfn = nf_nat_follow_master; 44 45 /* Try to get same port: if not, try to change it. */ 46 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { 47 int res; 48 49 exp->tuple.dst.u.tcp.port = htons(port); 50 res = nf_ct_expect_related(exp); 51 if (res == 0) 52 break; 53 else if (res != -EBUSY) { 54 port = 0; 55 break; 56 } 57 } 58 59 if (port == 0) { 60 nf_ct_helper_log(skb, exp->master, "all ports in use"); 61 return NF_DROP; 62 } 63 64 sprintf(buffer, "%u", port); 65 if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, 66 protoff, matchoff, matchlen, 67 buffer, strlen(buffer))) { 68 nf_ct_helper_log(skb, exp->master, "cannot mangle packet"); 69 nf_ct_unexpect_related(exp); 70 return NF_DROP; 71 } 72 return NF_ACCEPT; 73 } 74 75 static void __exit nf_nat_amanda_fini(void) 76 { 77 RCU_INIT_POINTER(nf_nat_amanda_hook, NULL); 78 synchronize_rcu(); 79 } 80 81 static int __init nf_nat_amanda_init(void) 82 { 83 BUG_ON(nf_nat_amanda_hook != NULL); 84 RCU_INIT_POINTER(nf_nat_amanda_hook, help); 85 return 0; 86 } 87 88 module_init(nf_nat_amanda_init); 89 module_exit(nf_nat_amanda_fini); 90