-/*
- * H.323 'brute force' extension for NAT alteration.
+/*
+ * H.323 'brute force' extension for NAT alteration.
* Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * (c) 2005 Max Kellermann <max@duempel.org>
*
* Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
* (http://www.coritel.it/projects/sofia/nat.html)
/* FIXME: Time out? --RR */
-static unsigned int
+static unsigned int
h225_nat_expected(struct sk_buff **pskb,
unsigned int hooknum,
struct ip_conntrack *ct,
static unsigned int h225_nat_help(struct ip_conntrack *ct,
struct ip_conntrack_expect *exp,
- struct ip_nat_info *info,
- enum ip_conntrack_info ctinfo,
- unsigned int hooknum,
- struct sk_buff **pskb);
-
-static struct ip_nat_helper h245 =
- { { NULL, NULL },
- "H.245", /* name */
- 0, /* flags */
- NULL, /* module */
- { { 0, { 0 } }, /* tuple */
- { 0, { 0 }, IPPROTO_TCP } },
- { { 0, { 0xFFFF } }, /* mask */
- { 0, { 0 }, 0xFFFF } },
- h225_nat_help, /* helper */
- h225_nat_expected /* expectfn */
- };
+ struct ip_nat_info *info,
+ enum ip_conntrack_info ctinfo,
+ unsigned int hooknum,
+ struct sk_buff **pskb);
+
+static struct ip_nat_helper h245 = {
+ .list = { NULL, NULL },
+ .name = "H.245",
+ .flags = 0,
+ .me = THIS_MODULE,
+ .tuple = { .src = { .ip = 0,
+ .u = { .tcp = { .port = 0 } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = IPPROTO_TCP
+ }
+ },
+ .mask = { .src = { .ip = 0,
+ .u = { .tcp = { .port = 0xffff } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = 0xffff
+ }
+ },
+ .help = h225_nat_help,
+ .expect = h225_nat_expected
+};
static unsigned int
h225_nat_expected(struct sk_buff **pskb,
struct ip_ct_h225_master *master_info;
struct ip_conntrack *master = master_ct(ct);
unsigned int is_h225, ret;
-
+
IP_NF_ASSERT(info);
IP_NF_ASSERT(master);
port = exp_info->port;
is_h225 = master_info->is_h225 == H225_PORT;
UNLOCK_BH(&ip_h323_lock);
-
+
if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
newip = newsrcip;
else
DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
- mr.rangesize = 1;
/* We don't want to manip the per-protocol, just the IPs... */
+ mr.rangesize = 1;
mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
mr.range[0].min_ip = mr.range[0].max_ip = newip;
}
ret = ip_nat_setup_info(ct, &mr, hooknum);
-
+
if (is_h225) {
DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
/* NAT expectfn called with ip_nat_lock write-locked */
}
static int h323_signal_address_fixup(struct ip_conntrack *ct,
- struct sk_buff **pskb,
- enum ip_conntrack_info ctinfo)
+ struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo)
{
struct iphdr *iph = (*pskb)->nh.iph;
- struct tcphdr *tcph = (void *)iph + iph->ihl*4;
- char *data = (char *) tcph + tcph->doff * 4;
- u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
- u_int32_t datalen = tcplen - tcph->doff*4;
- struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
- u_int32_t newip;
- u_int16_t port;
+ struct tcphdr _tcph, *tcph;
+ u_int32_t tcplen, datalen;
+ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
+ struct {
+ u_int32_t ip;
+ u_int16_t port;
+ } __attribute__ ((__packed__)) newdata;
int i;
+ int ret;
+
+ tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
+ if (tcph == NULL)
+ return NF_ACCEPT;
+
+ tcplen = (*pskb)->len - iph->ihl * 4;
+ datalen = tcplen - tcph->doff * 4;
MUST_BE_LOCKED(&ip_h323_lock);
|| between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
return 1;
- DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
- info->offset[IP_CT_DIR_ORIGINAL],
+ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
+ info->offset[IP_CT_DIR_ORIGINAL],
info->offset[IP_CT_DIR_REPLY],
tcplen);
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
DEBUGP("h323_signal_address_fixup: %s %s\n",
info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
- if (!between(info->seq[i], ntohl(tcph->seq),
+ if (!between(info->seq[i], ntohl(tcph->seq),
ntohl(tcph->seq) + datalen))
continue;
if (!between(info->seq[i] + 6, ntohl(tcph->seq),
/* Change address inside packet to match way we're mapping
this connection. */
if (i == IP_CT_DIR_ORIGINAL) {
- newip = ct->tuplehash[!info->dir].tuple.dst.ip;
- port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
+ newdata.ip = ct->tuplehash[!info->dir].tuple.dst.ip;
+ newdata.port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
} else {
- newip = ct->tuplehash[!info->dir].tuple.src.ip;
- port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
+ newdata.ip = ct->tuplehash[!info->dir].tuple.src.ip;
+ newdata.port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
}
- DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
- i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
- NIPQUAD(*((u_int32_t *)(data + info->offset[i]))),
- ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
-
/* Modify the packet */
- *(u_int32_t *)(data + info->offset[i]) = newip;
- *(u_int16_t *)(data + info->offset[i] + 4) = port;
-
- DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
- i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
- NIPQUAD(*((u_int32_t *)(data + info->offset[i]))),
- ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
+ ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ info->seq[i] - ntohl(tcph->seq),
+ sizeof(newdata),
+ (const char*)&newdata, sizeof(newdata));
+ if (!ret)
+ return 0;
}
- /* fix checksum information */
-
- (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
- datalen, 0);
-
- tcph->check = 0;
- tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
- csum_partial((char *)tcph, tcph->doff*4,
- (*pskb)->csum));
- ip_send_check(iph);
-
return 1;
}
enum ip_conntrack_info ctinfo,
struct ip_conntrack_expect *expect)
{
- u_int32_t newip;
- u_int16_t port;
+ struct {
+ u_int32_t ip;
+ u_int16_t port;
+ } __attribute__ ((__packed__)) newdata;
struct ip_conntrack_tuple newtuple;
struct iphdr *iph = (*pskb)->nh.iph;
- struct tcphdr *tcph = (void *)iph + iph->ihl*4;
- char *data = (char *) tcph + tcph->doff * 4;
- u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
+ struct tcphdr _tcph, *tcph;
+ u_int32_t tcplen;
struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
int is_h225;
+ int ret;
+
+ tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
+ if (tcph == NULL)
+ return NF_ACCEPT;
+
+ tcplen = (*pskb)->len - iph->ihl * 4;
MUST_BE_LOCKED(&ip_h323_lock);
DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
this connection. */
if (info->dir == IP_CT_DIR_REPLY) {
/* Must be where client thinks server is */
- newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+ newdata.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
/* Expect something from client->server */
newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
} else {
/* Must be where server thinks client is */
- newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+ newdata.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
/* Expect something from server->client */
newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
newtuple.dst.protonum = IPPROTO_UDP;
newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
}
-
+
/* Try to get same port: if not, try to change it. */
- for (port = ntohs(info->port); port != 0; port++) {
+ for (newdata.port = ntohs(info->port); newdata.port != 0; newdata.port++) {
if (is_h225)
- newtuple.dst.u.tcp.port = htons(port);
+ newtuple.dst.u.tcp.port = htons(newdata.port);
else
- newtuple.dst.u.udp.port = htons(port);
+ newtuple.dst.u.udp.port = htons(newdata.port);
if (ip_conntrack_change_expect(expect, &newtuple) == 0)
break;
}
- if (port == 0) {
+ if (newdata.port == 0) {
DEBUGP("h323_data_fixup: no free port found!\n");
return 0;
}
- port = htons(port);
-
- DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
- NIPQUAD(*((u_int32_t *)(data + info->offset))),
- ntohs(*((u_int16_t *)(data + info->offset + 4))));
+ newdata.port = htons(newdata.port);
/* Modify the packet */
- *(u_int32_t *)(data + info->offset) = newip;
- *(u_int16_t *)(data + info->offset + 4) = port;
-
- DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
- NIPQUAD(*((u_int32_t *)(data + info->offset))),
- ntohs(*((u_int16_t *)(data + info->offset + 4))));
-
- /* fix checksum information */
- /* FIXME: usually repeated multiple times in the case of H.245! */
-
- (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
- tcplen - tcph->doff*4, 0);
-
- tcph->check = 0;
- tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
- csum_partial((char *)tcph, tcph->doff*4,
- (*pskb)->csum));
- ip_send_check(iph);
+ ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+ expect->seq - ntohl(tcph->seq),
+ sizeof(newdata),
+ (const char*)&newdata, sizeof(newdata));
+ if (!ret)
+ return 0;
return 1;
}
static unsigned int h225_nat_help(struct ip_conntrack *ct,
struct ip_conntrack_expect *exp,
- struct ip_nat_info *info,
- enum ip_conntrack_info ctinfo,
- unsigned int hooknum,
- struct sk_buff **pskb)
+ struct ip_nat_info *info,
+ enum ip_conntrack_info ctinfo,
+ unsigned int hooknum,
+ struct sk_buff **pskb)
{
int dir;
struct ip_ct_h225_expect *exp_info;
-
+
/* Only mangle things once: original direction in POST_ROUTING
and reply direction on PRE_ROUTING. */
dir = CTINFO2DIR(ctinfo);
UNLOCK_BH(&ip_h323_lock);
return NF_ACCEPT;
}
-
+
exp_info = &exp->help.exp_h225_info;
LOCK_BH(&ip_h323_lock);
return NF_ACCEPT;
}
-static struct ip_nat_helper h225 =
- { { NULL, NULL },
- "H.225", /* name */
- IP_NAT_HELPER_F_ALWAYS, /* flags */
- THIS_MODULE, /* module */
- { { 0, { .tcp = { __constant_htons(H225_PORT) } } }, /* tuple */
- { 0, { 0 }, IPPROTO_TCP } },
- { { 0, { .tcp = { 0xFFFF } } }, /* mask */
- { 0, { 0 }, 0xFFFF } },
- h225_nat_help, /* helper */
- h225_nat_expected /* expectfn */
- };
+static struct ip_nat_helper h225 = {
+ .list = { NULL, NULL },
+ .name = "H.225",
+ .flags = IP_NAT_HELPER_F_ALWAYS,
+ .me = THIS_MODULE,
+ .tuple = { .src = { .ip = 0,
+ .u = { .tcp = { .port =
+ __constant_htons(H225_PORT) } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = IPPROTO_TCP
+ }
+ },
+ .mask = { .src = { .ip = 0,
+ .u = { .tcp = { .port = 0xffff } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = 0xffff
+ }
+ },
+ .help = h225_nat_help,
+ .expect = h225_nat_expected
+};
static int __init init(void)
{
int ret;
-
+
+ printk("ip_nat_h323: initialize the module!\n");
ret = ip_nat_helper_register(&h225);
if (ret != 0)
ip_nat_helper_unregister(&h225);
}
+NEEDS_CONNTRACK(h225);
+NEEDS_CONNTRACK(h245);
module_init(init);
module_exit(fini);