diff -NurpP --minimal linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack.h 2006-12-14 11:38:12.000000000 +0100 +++ linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack.h 2006-12-14 11:40:54.000000000 +0100 @@ -28,6 +28,7 @@ union ip_conntrack_expect_proto { }; /* Add protocol helper include file here */ +#include #include #include #include @@ -39,6 +40,7 @@ union ip_conntrack_expect_proto { /* per conntrack: application helper private data */ union ip_conntrack_help { /* insert conntrack helper private data (master) here */ + struct ip_ct_talk_master ct_talk_info; struct ip_ct_rsh_master ct_rsh_info; struct ip_ct_mms_master ct_mms_info; struct ip_ct_h323_master ct_h323_info; diff -NurpP --minimal linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack_talk.h linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack_talk.h --- linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack_talk.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack_talk.h 2006-12-14 11:40:54.000000000 +0100 @@ -0,0 +1,163 @@ +#ifndef _IP_CONNTRACK_TALK_H +#define _IP_CONNTRACK_TALK_H +/* TALK tracking. */ + +#ifdef __KERNEL__ +#include +#include + +/* Protects talk part of conntracks */ +DECLARE_LOCK_EXTERN(ip_talk_lock); +#endif + + +#define TALK_PORT 517 +#define NTALK_PORT 518 + +/* talk structures and constants from */ + +/* + * 4.3BSD struct sockaddr + */ +struct talk_addr { + u_int16_t ta_family; + u_int16_t ta_port; + u_int32_t ta_addr; + u_int32_t ta_junk1; + u_int32_t ta_junk2; +}; + +#define TALK_OLD_NSIZE 9 +#define TALK_NSIZE 12 +#define TALK_TTY_NSIZE 16 + +/* + * Client->server request message formats. + */ +struct talk_msg { + u_char type; /* request type, see below */ + char l_name[TALK_OLD_NSIZE];/* caller's name */ + char r_name[TALK_OLD_NSIZE];/* callee's name */ + u_char pad; + u_int32_t id_num; /* message id */ + int32_t pid; /* caller's process id */ + char r_tty[TALK_TTY_NSIZE];/* callee's tty name */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ +}; + +struct ntalk_msg { + u_char vers; /* protocol version */ + u_char type; /* request type, see below */ + u_char answer; /* not used */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ + int32_t pid; /* caller's process id */ + char l_name[TALK_NSIZE];/* caller's name */ + char r_name[TALK_NSIZE];/* callee's name */ + char r_tty[TALK_TTY_NSIZE];/* callee's tty name */ +}; + +struct ntalk2_msg { + u_char vers; /* talk protocol version */ + u_char type; /* request type */ + u_char answer; /* */ + u_char extended; /* !0 if additional parts */ + u_int32_t id_num; /* message id number (dels) */ + struct talk_addr addr; /* target address */ + struct talk_addr ctl_addr; /* reply to address */ + int32_t pid; /* caller's process id */ + char l_name[TALK_NSIZE]; /* caller's name */ + char r_name[TALK_NSIZE]; /* callee's name */ + char r_tty[TALK_TTY_NSIZE]; /* callee's tty */ +}; + +/* + * Server->client response message formats. + */ +struct talk_response { + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad[2]; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk2_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message */ + u_char answer; /* response to request */ + u_char rvers; /* Version of answering vers*/ + u_int32_t id_num; /* message id number */ + struct talk_addr addr; /* address for connection */ + /* This is at the end to compatiblize this with NTALK version. */ + char r_name[TALK_NSIZE]; /* callee's name */ +}; + +#define TALK_STR(data, talk_str, member) ((struct talk_str *)data)->member) +#define TALK_RESP(data, ver, member) (ver ? ((struct ntalk_response *)data)->member : ((struct talk_response *)data)->member) +#define TALK_MSG(data, ver, member) (ver ? ((struct ntalk_msg *)data)->member : ((struct talk_msg *)data)->member) + +#define TALK_VERSION 0 /* protocol versions */ +#define NTALK_VERSION 1 +#define NTALK2_VERSION 2 + +/* message type values */ +#define LEAVE_INVITE 0 /* leave invitation with server */ +#define LOOK_UP 1 /* check for invitation by callee */ +#define DELETE 2 /* delete invitation by caller */ +#define ANNOUNCE 3 /* announce invitation by caller */ +/* NTALK2 */ +#define REPLY_QUERY 4 /* request reply data from local daemon */ + +/* answer values */ +#define SUCCESS 0 /* operation completed properly */ +#define NOT_HERE 1 /* callee not logged in */ +#define FAILED 2 /* operation failed for unexplained reason */ +#define MACHINE_UNKNOWN 3 /* caller's machine name unknown */ +#define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */ +#define UNKNOWN_REQUEST 5 /* request has invalid type value */ +#define BADVERSION 6 /* request has invalid protocol version */ +#define BADADDR 7 /* request has invalid addr value */ +#define BADCTLADDR 8 /* request has invalid ctl_addr value */ +/* NTALK2 */ +#define NO_CALLER 9 /* no-one calling answer from REPLY */ +#define TRY_HERE 10 /* Not on this machine, try this */ +#define SELECTIVE_REFUSAL 11 /* User Filter refusal. */ +#define MAX_RESPONSE_TYPE 11 /* Make sure this is updated */ + +/* This structure exists only once per master */ +struct ip_ct_talk_master +{ +}; + +struct ip_conntrack; +struct ip_conntrack_expect; + +extern unsigned int (*ip_nat_talk_resp_hook)(struct sk_buff **pskb, + struct ip_conntrack_expect *exp, + u_char type, + u_char answer, + struct talk_addr *addr); + +extern unsigned int (*ip_nat_talk_msg_hook)(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_char type, + struct talk_addr *addr, + struct talk_addr *ctl_addr); + + +void ip_ct_talk_expect(struct ip_conntrack *ct, struct ip_conntrack_expect *exp); +void ip_ct_ntalk_expect(struct ip_conntrack *ct, struct ip_conntrack_expect *exp); +#endif /* _IP_CONNTRACK_TALK_H */ diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/Kconfig linux-2.6.19/net/ipv4/netfilter/Kconfig --- linux-2.6.19-pom-ng/net/ipv4/netfilter/Kconfig 2006-12-14 11:40:32.000000000 +0100 +++ linux-2.6.19/net/ipv4/netfilter/Kconfig 2006-12-14 11:40:54.000000000 +0100 @@ -909,5 +909,28 @@ config IP_NF_RTSP If you want to compile it as a module, say 'M' here and read Documentation/modules.txt. If unsure, say 'Y'. +config IP_NF_NAT_TALK + tristate + depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n + default IP_NF_NAT if IP_NF_TALK=y + default m if IP_NF_TALK=m + +config IP_NF_TALK + tristate 'talk protocol support' + depends on IP_NF_CONNTRACK + help + The talk protocols (both otalk/talk - or talk/ntalk, to confuse + you by the different namings about which is old or which is new :-) + use an additional channel to setup the talk session and a separated + data channel for the actual conversation (like in FTP). Both the + initiating and the setup channels are over UDP, while the data channel + is over TCP, on a random port. The conntrack part of this extension + will enable you to let in/out talk sessions easily by matching these + connections as RELATED by the state match, while the NAT part helps + you to let talk sessions trough a NAT machine. + + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'N'. + endmenu diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/Makefile linux-2.6.19/net/ipv4/netfilter/Makefile --- linux-2.6.19-pom-ng/net/ipv4/netfilter/Makefile 2006-12-14 11:40:32.000000000 +0100 +++ linux-2.6.19/net/ipv4/netfilter/Makefile 2006-12-14 11:40:54.000000000 +0100 @@ -25,6 +25,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o # connection tracking helpers +obj-$(CONFIG_IP_NF_TALK) += ip_conntrack_talk.o # rtsp protocol support obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o @@ -43,6 +44,7 @@ obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_ obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o # NAT helpers +obj-$(CONFIG_IP_NF_NAT_TALK) += ip_nat_talk.o obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_conntrack_talk.c linux-2.6.19/net/ipv4/netfilter/ip_conntrack_talk.c --- linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_conntrack_talk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.19/net/ipv4/netfilter/ip_conntrack_talk.c 2006-12-14 11:40:54.000000000 +0100 @@ -0,0 +1,449 @@ +/* + * talk extension for IP connection tracking. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[01] + * + * talk=[0|1] disable|enable old talk support + * ntalk=[0|1] disable|enable ntalk support + * ntalk2=[0|1] disable|enable ntalk2 support + * + * The default is talk=1 ntalk=1 ntalk2=1 + * + * The helper does not support simultaneous talk requests. + ** + * + * ASCII art on talk protocols + * + * + * caller server callee server + * | \ / + * | \ / + * | \ / + * | / + * | / \ + * 2 | 1 / \ 3 + * caller client ----------- callee client + * 4 + * + * 1. caller client <-> callee server: LOOK_UP, then ANNOUNCE invitation + * ( 2. caller client <-> caller server: LEAVE_INVITE to server ) + * 3. callee client <-> caller server: LOOK_UP invitation + * 4. callee client <-> caller client: talk data channel + * + * [1]: M. Hunter, talk: a historical protocol for interactive communication + * draft-hunter-talk-00.txt + * [2]: D.B. Chapman, E.D. Zwicky: Building Internet Firewalls (O'Reilly) + * + * Modifications: + * 2005-02-13 Harald Welte + * - update to 2.6.x API + * - update to post 2.6.11 helper infrastructure + * - use c99 structure initializers + * - explicitly allocate expectation + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Default all talk protocols are supported */ +static int talk = 1; +static int ntalk = 1; +static int ntalk2 = 1; +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk connection tracking module"); +MODULE_LICENSE("GPL"); +module_param(talk, int, 0400); +MODULE_PARM_DESC(talk, "support (old) talk protocol"); +module_param(ntalk, int, 0400); +MODULE_PARM_DESC(ntalk, "support ntalk protocol"); +module_param(ntalk2, int, 0400); +MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol"); + +static char talk_buffer[65536]; +static DECLARE_LOCK(talk_buffer_lock); + +unsigned int (*ip_nat_talk_resp_hook)(struct sk_buff **pskb, + struct ip_conntrack_expect *exp, + u_char type, + u_char answer, + struct talk_addr *addr); +EXPORT_SYMBOL_GPL(ip_nat_talk_resp_hook); + +unsigned int (*ip_nat_talk_msg_hook)(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_char type, + struct talk_addr *addr, + struct talk_addr *ctl_addr); +EXPORT_SYMBOL_GPL(ip_nat_talk_msg_hook); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +void ip_ct_talk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); +void ip_ct_ntalk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); + +static void (*talk_expectfn[2])(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) = { + ip_ct_talk_expect, + ip_ct_ntalk_expect }; + +static int talk_help_response(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port, + u_char mode, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + int ret; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect *exp; + u_int16_t exp_talk_port; + + DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + type, answer); + + if (!(answer == SUCCESS && type == mode)) + return NF_ACCEPT; + + exp = ip_conntrack_expect_alloc(); + if (exp == NULL) { + return NF_DROP; + } + + if (type == ANNOUNCE) { + + DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n"); + + /* update the talk info */ + exp_talk_port = htons(talk_port); + + /* expect callee client -> caller server message */ + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[dir].tuple.src.ip, + { 0 } }, + { ct->tuplehash[dir].tuple.dst.ip, + { .udp = { htons(talk_port) } }, + IPPROTO_UDP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); + + exp->expectfn = talk_expectfn[talk_port - TALK_PORT]; + exp->master = ct; + + DEBUGP("ip_ct_talk_help_response: callee client " + "%u.%u.%u.%u:%u -> caller daemon %u.%u.%u.%u:%u!\n", + NIPQUAD(exp->tuple.src.ip), + ntohs(exp->tuple.src.u.udp.port), + NIPQUAD(exp->tuple.dst.ip), + ntohs(exp->tuple.dst.u.udp.port)); + + if (ip_nat_talk_resp_hook) + ret = ip_nat_talk_resp_hook(pskb, exp, type, answer, + addr); + else if (ip_conntrack_expect_related(exp) != 0) { + ip_conntrack_expect_free(exp); + ret = NF_DROP; + } + } else if (type == LOOK_UP) { + + DEBUGP("ip_ct_talk_help_response: LOOK_UP\n"); + + /* update the talk info */ + exp_talk_port = addr->ta_port; + + /* expect callee client -> caller client connection */ + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, + { 0 } }, + { addr->ta_addr, + { addr->ta_port }, + IPPROTO_TCP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFF }}); + exp->expectfn = NULL; + exp->master = ct; + + DEBUGP("ip_ct_talk_help_response: callee client " + "%u.%u.%u.%u:%u -> caller client %u.%u.%u.%u:%u!\n", + NIPQUAD(exp->tuple.src.ip), + ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), + ntohs(exp->tuple.dst.u.tcp.port)); + + if (ip_nat_talk_resp_hook) + ret = ip_nat_talk_resp_hook(pskb, exp, type, answer, + addr); + else if (ip_conntrack_expect_related(exp) != 0) { + ip_conntrack_expect_free(exp); + ret = NF_DROP; + } + } + + return NF_ACCEPT; +} + +/* FIXME: This should be in userspace. Later. */ +static int talk_help(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port, + u_char mode) +{ + int ret; + unsigned int dataoff; + struct udphdr _udph, *uh; + char *tb_ptr, *data; + //struct udphdr *udph = (void *)iph + iph->ihl * 4; + //const char *data = (const char *)udph + sizeof(struct udphdr); + int dir = CTINFO2DIR(ctinfo); + size_t udplen; + + DEBUGP("ip_ct_talk_help: help entered\n"); + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ip_ct_talk_help: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole UDP header? */ + uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, + sizeof(_udph), &_udph); + if (uh == NULL) { + DEBUGP("ip_ct_talk_help: short for udph\n"); + return NF_ACCEPT; + } + + udplen = (*pskb)->len - (*pskb)->nh.iph->ihl*4; + dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(_udph); + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + LOCK_BH(&talk_buffer_lock); + tb_ptr = skb_header_pointer(*pskb, dataoff, + (*pskb)->len - dataoff, talk_buffer); + BUG_ON(tb_ptr == NULL); + + data = tb_ptr; + + DEBUGP("ip_ct_talk_help: %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(udph->source), NIPQUAD(iph->daddr), ntohs(udph->dest)); + + if (dir == IP_CT_DIR_ORIGINAL && ip_nat_talk_msg_hook) { + if (talk_port == TALK_PORT) { + if (udplen == sizeof(struct udphdr) + + sizeof(struct talk_msg)) { + struct talk_msg *tm = (struct talk_msg *)data; + return ip_nat_talk_msg_hook(pskb, ct, tm->type, + &tm->addr, &tm->ctl_addr); + } + } else { + if (ntalk && + udplen == sizeof(struct udphdr) + + sizeof(struct ntalk_msg) && + ((struct ntalk_msg *)data)->vers == NTALK_VERSION){ + struct ntalk_msg *tm = (struct ntalk_msg *)data; + return ip_nat_talk_msg_hook(pskb, ct, tm->type, + &tm->addr, &tm->ctl_addr); + } else if (ntalk2 && + udplen >= sizeof(struct udphdr) + + sizeof(struct ntalk2_msg) && + ((struct ntalk2_msg *)data)->vers == NTALK2_VERSION && + udplen == sizeof(struct udphdr) + + sizeof(struct ntalk2_msg) + + ((struct ntalk2_msg *)data)->extended) { + struct ntalk2_msg *tm = (struct ntalk2_msg *)data; + return ip_nat_talk_msg_hook(pskb, ct, tm->type, + &tm->addr, &tm->ctl_addr); + } + } + return NF_ACCEPT; + } + + /* only DIR_REPLY */ + if (talk_port == TALK_PORT + && udplen == sizeof(struct udphdr) + sizeof(struct talk_response)) + ret = talk_help_response(pskb, ct, ctinfo, talk_port, mode, + ((struct talk_response *)data)->type, + ((struct talk_response *)data)->answer, + &(((struct talk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response) + && ((struct ntalk_response *)data)->vers == NTALK_VERSION) + ret = talk_help_response(pskb, ct, ctinfo, talk_port, mode, + ((struct ntalk_response *)data)->type, + ((struct ntalk_response *)data)->answer, + &(((struct ntalk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response) + && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION) + ret = talk_help_response(pskb, ct, ctinfo, talk_port, mode, + ((struct ntalk2_response *)data)->type, + ((struct ntalk2_response *)data)->answer, + &(((struct ntalk2_response *)data)->addr)); + else { + DEBUGP("ip_ct_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_response), sizeof(struct ntalk2_response)); + ret = NF_ACCEPT; + } + UNLOCK_BH(&talk_buffer_lock); + return ret; +} + +static int lookup_help(struct sk_buff **pskb, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(pskb, ct, ctinfo, TALK_PORT, LOOK_UP); +} + +static int lookup_nhelp(struct sk_buff **pskb, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(pskb, ct, ctinfo, NTALK_PORT, LOOK_UP); +} + +static struct ip_conntrack_helper lookup_helpers[2] = { + { + .name = "talk-lookup", + .max_expected = 1, + .timeout = 4 * 60, + .tuple = { + .src.u.udp.port = __constant_htons(TALK_PORT), + .dst.protonum = IPPROTO_UDP, + }, + .mask = { + .src.u.udp.port = 0xffff, + .dst.protonum = 0xff, + }, + .help = &lookup_help, + }, + { + .name = "ntalk-lookup", + .max_expected = 1, + .timeout = 4 * 60, + .tuple = { + .src.u.udp.port = __constant_htons(NTALK_PORT), + .dst.protonum = IPPROTO_UDP, + }, + .mask = { + .src.u.udp.port = 0xffff, + .dst.protonum = 0xff, + }, + .help = &lookup_nhelp, + }, +}; + +void ip_ct_talk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + DEBUGP("ip_conntrack_talk: calling talk_expectfn for ct %p\n", ct); + WRITE_LOCK(&ip_conntrack_lock); + ct->helper = &lookup_helpers[0]; + WRITE_UNLOCK(&ip_conntrack_lock); +} + +void ip_ct_ntalk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + DEBUGP("ip_conntrack_talk: calling ntalk_expectfn for ct %p\n", ct); + WRITE_LOCK(&ip_conntrack_lock); + ct->helper = &lookup_helpers[1]; + WRITE_UNLOCK(&ip_conntrack_lock); +} + +static int help(struct sk_buff **pskb, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(pskb, ct, ctinfo, TALK_PORT, ANNOUNCE); +} + +static int nhelp(struct sk_buff **pskb, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(pskb, ct, ctinfo, NTALK_PORT, ANNOUNCE); +} + +static struct ip_conntrack_helper talk_helpers[2] = { + { + .name = "talk", + .help = &help, + .me = THIS_MODULE, + .max_expected = 1, + .timeout = 4 * 60, /* 4 minutes */ + .tuple = { + .src.u.udp.port = __constant_htons(TALK_PORT), + .dst.protonum = IPPROTO_UDP, + }, + .mask = { + .src.u.udp.port = 0xffff, + .dst.protonum = 0xff, + }, + }, + { + .name = "ntalk", + .help = &nhelp, + .me = THIS_MODULE, + .max_expected = 1, + .timeout = 4 * 60, /* 4 minutes */ + .tuple = { + .src.u.udp.port = __constant_htons(NTALK_PORT), + .dst.protonum = IPPROTO_UDP, + }, + .mask = { + .src.u.udp.port = 0xffff, + .dst.protonum = IPPROTO_UDP, + }, + }, +}; + +static int __init init(void) +{ + if (talk > 0) + ip_conntrack_helper_register(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_register(&talk_helpers[1]); + + return 0; +} + +static void __exit fini(void) +{ + if (talk > 0) + ip_conntrack_helper_unregister(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_unregister(&talk_helpers[1]); +} + +module_init(init); +module_exit(fini); diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_nat_talk.c linux-2.6.19/net/ipv4/netfilter/ip_nat_talk.c --- linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_nat_talk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.19/net/ipv4/netfilter/ip_nat_talk.c 2006-12-14 11:40:54.000000000 +0100 @@ -0,0 +1,226 @@ +/* + * talk extension for UDP NAT alteration. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * + * Modifications: + * 2005-02-13 Harald Welte + * - update to 2.6.x API + * - update to post 2.6.11 helper infrastructure + * - use c99 structure initializers + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk network address translation module"); + +#if 0 +#define DEBUGP printk +#define IP_NAT_TALK_DEBUG +#else +#define DEBUGP(format, args...) +#endif + +static void +nat_talk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + ip_nat_follow_master(ct, exp); + ip_ct_talk_expect(ct, exp); +} + +static void +nat_ntalk_expect(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + ip_nat_follow_master(ct, exp); + ip_ct_ntalk_expect(ct, exp); +} + +static int +mangle_packet(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_int32_t newip, + u_int16_t port, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + size_t udplen = (*pskb)->len - iph->ihl * 4; + + /* Fortunately talk sends a structure with the address and + port in it. The size of the packet won't change. */ + + if (ctl_addr == NULL) { + /* response */ + if (addr->ta_addr == INADDR_ANY) + return 1; + DEBUGP("ip_nat_talk_mangle_packet: response orig " + "%u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(newip), ntohs(port)); + addr->ta_addr = newip; + addr->ta_port = port; + } else { + /* message */ + if (addr->ta_addr != INADDR_ANY) { + /* Change address inside packet to match way we're + * mapping this connection. */ + DEBUGP("ip_nat_talk_mangle_packet: message orig addr " + "%u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(addr->ta_port)); + addr->ta_addr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } + DEBUGP("ip_nat_talk_mangle_packet: message orig ctl_addr " + "%u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + NIPQUAD(newip), ntohs(port)); + ctl_addr->ta_addr = newip; + ctl_addr->ta_port = port; + } + + /* Fix checksums */ + (*pskb)->csum = csum_partial((char *)udph + sizeof(struct udphdr), udplen - sizeof(struct udphdr), 0); + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, sizeof(struct udphdr), (*pskb)->csum)); + + ip_send_check(iph); + return 1; +} + +static unsigned int talk_help_msg(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_char type, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + u_int32_t newip; + u_int16_t port; + + unsigned int verdict = NF_ACCEPT; + + DEBUGP("ip_nat_talk_help_msg: addr: %u.%u.%u.%u:%u, ctl_addr: %u.%u.%u.%u:%u, type %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + type); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + DEBUGP("ip_nat_talk_help_msg: inserting: %u.%u.%u.%u:%u\n", + NIPQUAD(newip), ntohs(port)); + + if (!mangle_packet(pskb, ct, newip, port, addr, ctl_addr)) + verdict = NF_DROP; + + return verdict; +} + +static unsigned int talk_help_response(struct sk_buff **pskb, + struct ip_conntrack_expect *exp, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + struct ip_conntrack *ct = exp->master; + u_int32_t newip; + u_int16_t port, *pport, *tport; + + DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, " + "type %d answer %d\n", NIPQUAD(addr->ta_addr), + ntohs(addr->ta_port), type, answer); + + DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", + ntohs(exp->tuple.dst.u.tcp.port), + type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE"); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL : + IP_CT_DIR_REPLY].tuple.dst.ip; + /* We can read expect here without conntrack lock, since it's + only set in ip_conntrack_talk , with ip_talk_lock held + writable */ + if (type == LOOK_UP) { + pport = &exp->saved_proto.tcp.port; + tport = &exp->tuple.dst.u.tcp.port; + } else { + pport = &exp->saved_proto.udp.port; + tport = &exp->tuple.dst.u.udp.port; + } + + *pport = *tport; + + exp->tuple.dst.ip = newip; + + if (exp->expectfn == ip_ct_talk_expect) + exp->expectfn = nat_talk_expect; + else if (exp->expectfn == ip_ct_ntalk_expect) + exp->expectfn = nat_ntalk_expect; + else + BUG(); + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(*pport); port != 0; port++) { + *tport = htons(port); + + if (ip_conntrack_expect_related(exp) == 0) { + DEBUGP("ip_nat_talk_help_response: using " + "%u.%u.%u.%u:%u\n", NIPQUAD(newip), port); + break; + } + } + if (port == 0) { + ip_conntrack_expect_free(exp); + return NF_DROP; + } + + if (!mangle_packet(pskb, ct, newip, htons(port), addr, NULL)) { + ip_conntrack_unexpect_related(exp); + return NF_DROP; + } + return NF_ACCEPT; +} + +static int __init init(void) +{ + BUG_ON(ip_nat_talk_msg_hook); + BUG_ON(ip_nat_talk_resp_hook); + ip_nat_talk_msg_hook = &talk_help_msg; + ip_nat_talk_resp_hook = &talk_help_response; + return 0; +} + +static void __exit fini(void) +{ + ip_nat_talk_resp_hook = NULL; + ip_nat_talk_msg_hook = NULL; + /* Make sure noone calls it, meanwhile */ + synchronize_net(); +} + +module_init(init); +module_exit(fini);