0001
0002
0003
0004
0005
0006
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
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
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
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
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
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);