Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* IRC extension for TCP NAT alteration.
0003  *
0004  * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
0005  * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
0006  * based on a copy of RR's ip_nat_ftp.c
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/module.h>
0012 #include <linux/moduleparam.h>
0013 #include <linux/tcp.h>
0014 #include <linux/kernel.h>
0015 
0016 #include <net/netfilter/nf_nat.h>
0017 #include <net/netfilter/nf_nat_helper.h>
0018 #include <net/netfilter/nf_conntrack_helper.h>
0019 #include <net/netfilter/nf_conntrack_expect.h>
0020 #include <linux/netfilter/nf_conntrack_irc.h>
0021 
0022 #define NAT_HELPER_NAME "irc"
0023 
0024 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
0025 MODULE_DESCRIPTION("IRC (DCC) NAT helper");
0026 MODULE_LICENSE("GPL");
0027 MODULE_ALIAS_NF_NAT_HELPER(NAT_HELPER_NAME);
0028 
0029 static struct nf_conntrack_nat_helper nat_helper_irc =
0030     NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME);
0031 
0032 static unsigned int help(struct sk_buff *skb,
0033              enum ip_conntrack_info ctinfo,
0034              unsigned int protoff,
0035              unsigned int matchoff,
0036              unsigned int matchlen,
0037              struct nf_conntrack_expect *exp)
0038 {
0039     char buffer[sizeof("4294967296 65635")];
0040     struct nf_conn *ct = exp->master;
0041     union nf_inet_addr newaddr;
0042     u_int16_t port;
0043 
0044     /* Reply comes from server. */
0045     newaddr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3;
0046 
0047     exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
0048     exp->dir = IP_CT_DIR_REPLY;
0049     exp->expectfn = nf_nat_follow_master;
0050 
0051     /* Try to get same port: if not, try to change it. */
0052     for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
0053         int ret;
0054 
0055         exp->tuple.dst.u.tcp.port = htons(port);
0056         ret = nf_ct_expect_related(exp, 0);
0057         if (ret == 0)
0058             break;
0059         else if (ret != -EBUSY) {
0060             port = 0;
0061             break;
0062         }
0063     }
0064 
0065     if (port == 0) {
0066         nf_ct_helper_log(skb, ct, "all ports in use");
0067         return NF_DROP;
0068     }
0069 
0070     /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
0071      * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
0072      * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
0073      * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
0074      * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
0075      *
0076      * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
0077      *                        255.255.255.255==4294967296, 10 digits)
0078      * P:         bound port (min 1 d, max 5d (65635))
0079      * F:         filename   (min 1 d )
0080      * S:         size       (min 1 d )
0081      * 0x01, \n:  terminators
0082      */
0083     /* AAA = "us", ie. where server normally talks to. */
0084     snprintf(buffer, sizeof(buffer), "%u %u", ntohl(newaddr.ip), port);
0085     pr_debug("inserting '%s' == %pI4, port %u\n",
0086          buffer, &newaddr.ip, port);
0087 
0088     if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff,
0089                       matchlen, buffer, strlen(buffer))) {
0090         nf_ct_helper_log(skb, ct, "cannot mangle packet");
0091         nf_ct_unexpect_related(exp);
0092         return NF_DROP;
0093     }
0094 
0095     return NF_ACCEPT;
0096 }
0097 
0098 static void __exit nf_nat_irc_fini(void)
0099 {
0100     nf_nat_helper_unregister(&nat_helper_irc);
0101     RCU_INIT_POINTER(nf_nat_irc_hook, NULL);
0102     synchronize_rcu();
0103 }
0104 
0105 static int __init nf_nat_irc_init(void)
0106 {
0107     BUG_ON(nf_nat_irc_hook != NULL);
0108     nf_nat_helper_register(&nat_helper_irc);
0109     RCU_INIT_POINTER(nf_nat_irc_hook, help);
0110     return 0;
0111 }
0112 
0113 /* Prior to 2.6.11, we had a ports param.  No longer, but don't break users. */
0114 static int warn_set(const char *val, const struct kernel_param *kp)
0115 {
0116     pr_info("kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
0117     return 0;
0118 }
0119 module_param_call(ports, warn_set, NULL, NULL, 0);
0120 
0121 module_init(nf_nat_irc_init);
0122 module_exit(nf_nat_irc_fini);