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