All of lore.kernel.org
 help / color / mirror / Atom feed
* [H.323 Helper 5/5]: Add support for Call Forwarding
@ 2006-06-09  4:28 Jing Min Zhao
  2006-06-09 13:22 ` Jing Min Zhao
  2006-06-17 15:20 ` Patrick McHardy
  0 siblings, 2 replies; 3+ messages in thread
From: Jing Min Zhao @ 2006-06-09  4:28 UTC (permalink / raw)
  To: Netfilter Development Mailinglist; +Cc: Patrick McHardy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="GB18030", Size: 102 bytes --]

Add support for Call Forwarding.

Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>

[-- Attachment #2: patch5-call-forwarding --]
[-- Type: application/octet-stream, Size: 16867 bytes --]

diff -pruN linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2006-06-08 14:19:47.000000000 -0400
+++ linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack.h	2006-06-08 21:10:38.000000000 -0400
@@ -154,6 +154,7 @@ struct ip_conntrack_expect
 	unsigned int flags;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
+	u_int32_t saved_ip;
 	/* This is the original per-proto part, used to map the
 	 * expected connection the way the recipient expects. */
 	union ip_conntrack_manip_proto saved_proto;
diff -pruN linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack_h323.h
--- linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack_h323.h	2006-06-08 14:19:47.000000000 -0400
+++ linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack_h323.h	2006-06-08 21:11:31.000000000 -0400
@@ -29,6 +29,7 @@ struct ip_ct_h323_master {
 
 struct ip_conntrack_expect;
 
+extern int have_direct_route(u_int32_t src, u_int32_t dst);
 extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
 			 u_int32_t * ip, u_int16_t * port);
 extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
@@ -71,6 +72,13 @@ extern int (*nat_h245_hook) (struct sk_b
 			     unsigned char **data, int dataoff,
 			     TransportAddress * addr, u_int16_t port,
 			     struct ip_conntrack_expect * exp);
+extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
+				       struct ip_conntrack * ct,
+				       enum ip_conntrack_info ctinfo,
+				       unsigned char **data, int dataoff,
+				       TransportAddress * addr,
+				       u_int16_t port,
+				       struct ip_conntrack_expect * exp);
 extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
 			     enum ip_conntrack_info ctinfo,
 			     unsigned char **data, TransportAddress * addr,
diff -pruN linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
--- linux-2.6.17.orig/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h	2006-06-08 20:59:43.000000000 -0400
+++ linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h	2006-06-08 21:12:14.000000000 -0400
@@ -412,6 +412,7 @@ typedef struct Facility_UUIE {	/* SEQUEN
 		eFacility_UUIE_destinationInfo = (1 << 14),
 		eFacility_UUIE_h245SecurityMode = (1 << 13),
 	} options;
+	TransportAddress alternativeAddress;
 	FacilityReason reason;
 	TransportAddress h245Address;
 	Facility_UUIE_fastStart fastStart;
diff -pruN linux-2.6.17.orig/net/ipv4/netfilter/ip_conntrack_helper_h323.c linux-2.6.17/net/ipv4/netfilter/ip_conntrack_helper_h323.c
--- linux-2.6.17.orig/net/ipv4/netfilter/ip_conntrack_helper_h323.c	2006-06-08 21:08:53.000000000 -0400
+++ linux-2.6.17/net/ipv4/netfilter/ip_conntrack_helper_h323.c	2006-06-08 21:20:13.000000000 -0400
@@ -22,6 +22,8 @@
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
 #include <linux/moduleparam.h>
+#include <linux/ctype.h>
+#include <linux/inet.h>
 
 #if 0
 #define DEBUGP printk
@@ -38,6 +40,13 @@ static int gkrouted_only = 1;
 module_param(gkrouted_only, int, 0600);
 MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
 
+static char *internal_net = NULL;
+static u_int32_t internal_net_addr = 0;
+static u_int32_t internal_net_mask = 0;
+module_param(internal_net, charp, 0600);
+MODULE_PARM_DESC(internal_net, "specify your internal network using format "
+		 "address/mask");
+
 /* Hooks for NAT */
 int (*set_h245_addr_hook) (struct sk_buff ** pskb,
 			   unsigned char **data, int dataoff,
@@ -77,6 +86,12 @@ int (*nat_h245_hook) (struct sk_buff ** 
 		      unsigned char **data, int dataoff,
 		      TransportAddress * addr, u_int16_t port,
 		      struct ip_conntrack_expect * exp);
+int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
+				struct ip_conntrack * ct,
+				enum ip_conntrack_info ctinfo,
+				unsigned char **data, int dataoff,
+				TransportAddress * addr, u_int16_t port,
+				struct ip_conntrack_expect * exp);
 int (*nat_q931_hook) (struct sk_buff ** pskb,
 		      struct ip_conntrack * ct,
 		      enum ip_conntrack_info ctinfo,
@@ -88,6 +103,44 @@ static DEFINE_SPINLOCK(ip_h323_lock);
 static char *h323_buffer;
 
 /****************************************************************************/
+int have_direct_route(u_int32_t src, u_int32_t dst)
+{
+	struct flowi fl_src = {.fl4_dst = src };
+	struct flowi fl_dst = {.fl4_dst = dst };
+	struct rtable *rt_src, *rt_dst;
+	int ret = 0;
+
+	if (internal_net) {
+		if (((src & internal_net_mask) == internal_net_addr) ==
+		    ((dst & internal_net_mask) == internal_net_addr))
+			return 1;
+		return 0;
+	}
+
+	if (ip_route_output_key(&rt_dst, &fl_dst) != 0)
+		goto out;
+
+	if (ip_route_output_key(&rt_src, &fl_src) != 0)
+		goto out1;
+
+	if (rt_dst->u.dst.dev == rt_src->u.dst.dev &&
+	    rt_dst->rt_src == rt_src->rt_src) {
+		if ((rt_dst->u.dst.flags & DST_HOST) ||
+		    (rt_src->u.dst.flags & DST_HOST) ||
+		    (rt_dst->rt_gateway == rt_src->rt_gateway)) {
+			DEBUGP("ip_ct_h323: dst has direct route to src\n");
+			ret = 1;
+		}
+	}
+
+	dst_release(&rt_src->u.dst);
+      out1:
+	dst_release(&rt_dst->u.dst);
+      out:
+	return ret;
+}
+
+/****************************************************************************/
 static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned char **data, int *datalen, int *dataoff)
@@ -693,6 +746,73 @@ static int expect_h245(struct sk_buff **
 	return ret;
 }
 
+/* Forwarding declaration */
+void ip_conntrack_q931_expect(struct ip_conntrack *new,
+			      struct ip_conntrack_expect *this);
+
+/****************************************************************************/
+static int expect_callforwarding(struct sk_buff **pskb,
+				 struct ip_conntrack *ct,
+				 enum ip_conntrack_info ctinfo,
+				 unsigned char **data, int dataoff,
+				 TransportAddress * addr)
+{
+	int dir = CTINFO2DIR(ctinfo);
+	int ret = 0;
+	u_int32_t ip;
+	u_int16_t port;
+	struct ip_conntrack_expect *exp = NULL;
+
+	/* Read alternativeAddress */
+	if (!get_h225_addr(*data, addr, &ip, &port) || port == 0)
+		return 0;
+
+	/* If the calling party has direct route to the forward-to party,
+	 * we don't need to track the second call */
+	if (have_direct_route(ct->tuplehash[!dir].tuple.src.ip, ip)) {
+		DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
+		return 0;
+	}
+
+	/* Create expect for the second call leg */
+	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+		return -1;
+	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+	exp->tuple.src.u.tcp.port = 0;
+	exp->tuple.dst.ip = ip;
+	exp->tuple.dst.u.tcp.port = htons(port);
+	exp->tuple.dst.protonum = IPPROTO_TCP;
+	exp->mask.src.ip = 0xFFFFFFFF;
+	exp->mask.src.u.tcp.port = 0;
+	exp->mask.dst.ip = 0xFFFFFFFF;
+	exp->mask.dst.u.tcp.port = 0xFFFF;
+	exp->mask.dst.protonum = 0xFF;
+	exp->flags = 0;
+
+	if (ct->tuplehash[dir].tuple.src.ip !=
+	    ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) {
+		/* Need NAT */
+		ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff,
+					      addr, port, exp);
+	} else {		/* Conntrack only */
+		exp->expectfn = ip_conntrack_q931_expect;
+
+		if (ip_conntrack_expect_related(exp) == 0) {
+			DEBUGP("ip_ct_q931: expect Call Forwarding "
+			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\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));
+		} else
+			ret = -1;
+	}
+
+	ip_conntrack_expect_put(exp);
+
+	return ret;
+}
+
 /****************************************************************************/
 static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
@@ -888,6 +1008,15 @@ static int process_facility(struct sk_bu
 
 	DEBUGP("ip_ct_q931: Facility\n");
 
+	if (facility->reason.choice == eFacilityReason_callForwarded) {
+		if (facility->options & eFacility_UUIE_alternativeAddress)
+			return expect_callforwarding(pskb, ct, ctinfo, data,
+						     dataoff,
+						     &facility->
+						     alternativeAddress);
+		return 0;
+	}
+
 	if (facility->options & eFacility_UUIE_h245Address) {
 		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
 				  &facility->h245Address);
@@ -1680,6 +1809,7 @@ static void fini(void)
 static int __init init(void)
 {
 	int ret;
+	char *p;
 
 	h323_buffer = kmalloc(65536, GFP_KERNEL);
 	if (!h323_buffer)
@@ -1690,6 +1820,22 @@ static int __init init(void)
 		return ret;
 	}
 
+	if (internal_net) {
+		if ((p = strchr(internal_net, '/')))
+			*p++ = 0;
+		if (isdigit(internal_net[0])) {
+			internal_net_addr = in_aton(internal_net);
+			if (p && isdigit(p[0]))
+				internal_net_mask = in_aton(p);
+			else
+				internal_net_mask = 0xffffffff;
+			internal_net_addr &= internal_net_mask;
+		}
+		DEBUGP("ip_ct_h323: internal_net = %u.%u.%u.%u/%u.%u.%u.%u\n",
+		       NIPQUAD(internal_net_addr),
+		       NIPQUAD(internal_net_mask));
+	}
+
 	DEBUGP("ip_ct_h323: init success\n");
 	return 0;
 }
@@ -1698,6 +1844,7 @@ static int __init init(void)
 module_init(init);
 module_exit(fini);
 
+EXPORT_SYMBOL_GPL(have_direct_route);
 EXPORT_SYMBOL_GPL(get_h225_addr);
 EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect);
 EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect);
@@ -1708,6 +1855,7 @@ EXPORT_SYMBOL_GPL(set_ras_addr_hook);
 EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook);
 EXPORT_SYMBOL_GPL(nat_t120_hook);
 EXPORT_SYMBOL_GPL(nat_h245_hook);
+EXPORT_SYMBOL_GPL(nat_callforwarding_hook);
 EXPORT_SYMBOL_GPL(nat_q931_hook);
 
 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
diff -pruN linux-2.6.17.orig/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c linux-2.6.17/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
--- linux-2.6.17.orig/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c	2006-06-08 20:59:43.000000000 -0400
+++ linux-2.6.17/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c	2006-06-08 21:13:42.000000000 -0400
@@ -1069,8 +1069,8 @@ static field_t _Facility_UUIE_fastStart[
 
 static field_t _Facility_UUIE[] = {	/* SEQUENCE */
 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
-	{FNAME("alternativeAddress") CHOICE, 3, 7, 7, SKIP | EXT | OPT, 0,
-	 _TransportAddress},
+	{FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+	 offsetof(Facility_UUIE, alternativeAddress), _TransportAddress},
 	{FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
 	 _Facility_UUIE_alternativeAliasAddress},
 	{FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
diff -pruN linux-2.6.17.orig/net/ipv4/netfilter/ip_nat_helper_h323.c linux-2.6.17/net/ipv4/netfilter/ip_nat_helper_h323.c
--- linux-2.6.17.orig/net/ipv4/netfilter/ip_nat_helper_h323.c	2006-06-08 14:19:49.000000000 -0400
+++ linux-2.6.17/net/ipv4/netfilter/ip_nat_helper_h323.c	2006-06-08 21:25:13.000000000 -0400
@@ -30,6 +30,24 @@
 #endif
 
 /****************************************************************************/
+static u_int32_t get_source_ip(u_int32_t dst)
+{
+	struct rtable *rt;
+	struct flowi fl;
+	u_int32_t src;
+
+	memset(&fl, 0, sizeof(fl));
+	fl.fl4_dst = dst;
+	if (ip_route_output_key(&rt, &fl) != 0)
+		return 0;
+
+	src = rt->rt_src;
+
+	dst_release(&rt->u.dst);
+	return src;
+}
+
+/****************************************************************************/
 static int set_addr(struct sk_buff **pskb,
 		    unsigned char **data, int dataoff,
 		    unsigned int addroff, u_int32_t ip, u_int16_t port)
@@ -487,6 +505,87 @@ static int nat_q931(struct sk_buff **psk
 }
 
 /****************************************************************************/
+static void ip_nat_callforwarding_expect(struct ip_conntrack *new,
+					 struct ip_conntrack_expect *this)
+{
+	struct ip_nat_range range;
+	u_int32_t src_ip;
+
+	/* This must be a fresh one. */
+	BUG_ON(new->status & IPS_NAT_DONE_MASK);
+
+	/* Change src to where master sends to */
+	range.flags = IP_NAT_RANGE_MAP_IPS;
+	if (!have_direct_route(new->master->tuplehash[!this->dir].tuple.src.ip,
+			       this->saved_ip) &&
+	    (src_ip = get_source_ip(this->saved_ip)))
+		range.min_ip = range.max_ip = src_ip;
+	else
+		range.min_ip = range.max_ip =
+		    new->tuplehash[this->dir].tuple.src.ip;
+
+	/* hook doesn't matter, but it has to do source manip */
+	ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
+
+	/* For DST manip, map port here to where it's expected. */
+	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+	range.min = range.max = this->saved_proto;
+	range.min_ip = range.max_ip = this->saved_ip;
+
+	/* hook doesn't matter, but it has to do destination manip */
+	ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
+
+	ip_conntrack_q931_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct,
+			      enum ip_conntrack_info ctinfo,
+			      unsigned char **data, int dataoff,
+			      TransportAddress * addr, u_int16_t port,
+			      struct ip_conntrack_expect *exp)
+{
+	int dir = CTINFO2DIR(ctinfo);
+	u_int16_t nated_port;
+
+	/* Set expectations for NAT */
+	exp->saved_ip = exp->tuple.dst.ip;
+	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+	exp->expectfn = ip_nat_callforwarding_expect;
+	exp->dir = !dir;
+
+	/* Try to get same port: if not, try to change it. */
+	for (nated_port = port; nated_port != 0; nated_port++) {
+		exp->tuple.dst.u.tcp.port = htons(nated_port);
+		if (ip_conntrack_expect_related(exp) == 0)
+			break;
+	}
+
+	if (nated_port == 0) {	/* No port available */
+		if (net_ratelimit())
+			printk("ip_nat_q931: out of TCP ports\n");
+		return 0;
+	}
+
+	/* Modify signal */
+	if (!set_h225_addr(pskb, data, dataoff, addr,
+			   ct->tuplehash[!dir].tuple.dst.ip,
+			   nated_port) == 0) {
+		ip_conntrack_unexpect_related(exp);
+		return -1;
+	}
+
+	/* Success */
+	DEBUGP("ip_nat_q931: expect Call Forwarding "
+	       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\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));
+
+	return 0;
+}
+
+/****************************************************************************/
 static int __init init(void)
 {
 	BUG_ON(set_h245_addr_hook != NULL);
@@ -496,6 +595,7 @@ static int __init init(void)
 	BUG_ON(nat_rtp_rtcp_hook != NULL);
 	BUG_ON(nat_t120_hook != NULL);
 	BUG_ON(nat_h245_hook != NULL);
+	BUG_ON(nat_callforwarding_hook != NULL);
 	BUG_ON(nat_q931_hook != NULL);
 
 	set_h245_addr_hook = set_h245_addr;
@@ -505,6 +605,7 @@ static int __init init(void)
 	nat_rtp_rtcp_hook = nat_rtp_rtcp;
 	nat_t120_hook = nat_t120;
 	nat_h245_hook = nat_h245;
+	nat_callforwarding_hook = nat_callforwarding;
 	nat_q931_hook = nat_q931;
 
 	DEBUGP("ip_nat_h323: init success\n");
@@ -521,6 +622,7 @@ static void __exit fini(void)
 	nat_rtp_rtcp_hook = NULL;
 	nat_t120_hook = NULL;
 	nat_h245_hook = NULL;
+	nat_callforwarding_hook = NULL;
 	nat_q931_hook = NULL;
 	synchronize_net();
 }
diff -pruN linux-2.6.17.orig/net/ipv4/netfilter/Kconfig linux-2.6.17/net/ipv4/netfilter/Kconfig
--- linux-2.6.17.orig/net/ipv4/netfilter/Kconfig	2006-06-08 14:19:49.000000000 -0400
+++ linux-2.6.17/net/ipv4/netfilter/Kconfig	2006-06-08 21:27:13.000000000 -0400
@@ -181,10 +181,10 @@ config IP_NF_H323
 	  With this module you can support H.323 on a connection tracking/NAT
 	  firewall.
 
-	  This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP
-	  and T.120 based data and applications including audio, video, FAX,
-	  chat, whiteboard, file transfer, etc. For more information, please
-	  see http://nath323.sourceforge.net/.
+	  This module supports RAS, Fast Start, H.245 Tunnelling, Call
+	  Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat,
+	  whiteboard, file transfer, etc. For more information, please
+	  visit http://nath323.sourceforge.net/.
 
 	  If you want to compile it as a module, say 'M' here and read
 	  Documentation/modules.txt.  If unsure, say 'N'.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-06-17 15:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-09  4:28 [H.323 Helper 5/5]: Add support for Call Forwarding Jing Min Zhao
2006-06-09 13:22 ` Jing Min Zhao
2006-06-17 15:20 ` Patrick McHardy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.