|
@@ -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. this is used by call forwarding support");
|
|
|
+
|
|
|
/* 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 ** pskb,
|
|
|
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,
|
|
@@ -683,6 +698,76 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
|
|
|
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 is on the same side of the forward-to party,
|
|
|
+ * we don't need to track the second call */
|
|
|
+ if (internal_net &&
|
|
|
+ ((ip & internal_net_mask) == internal_net_addr) ==
|
|
|
+ ((ct->tuplehash[!dir].tuple.src.ip & internal_net_mask) ==
|
|
|
+ internal_net_addr)) {
|
|
|
+ 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,
|
|
@@ -878,6 +963,15 @@ static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct,
|
|
|
|
|
|
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);
|
|
@@ -1668,6 +1762,7 @@ static void fini(void)
|
|
|
static int __init init(void)
|
|
|
{
|
|
|
int ret;
|
|
|
+ char *p;
|
|
|
|
|
|
h323_buffer = kmalloc(65536, GFP_KERNEL);
|
|
|
if (!h323_buffer)
|
|
@@ -1678,6 +1773,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;
|
|
|
}
|
|
@@ -1696,6 +1807,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>");
|