2 * H.323 'brute force' extension for H.323 connection tracking.
3 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
4 * (c) 2005 Max Kellermann <max@duempel.org>
6 * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
7 * (http://www.coritel.it/projects/sofia/nat/)
8 * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
9 * the unregistered helpers to the conntrack entries.
13 #include <linux/module.h>
14 #include <linux/netfilter.h>
16 #include <net/checksum.h>
19 #include <linux/netfilter_ipv4/lockhelp.h>
20 #include <linux/netfilter_ipv4/ip_conntrack.h>
21 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
22 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
23 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
24 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
26 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
27 MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
28 MODULE_LICENSE("GPL");
30 /* This is slow, but it's simple. --RR */
31 static char h323_buffer[65536];
32 static DECLARE_LOCK(h323_buffer_lock);
34 DECLARE_LOCK(ip_h323_lock);
35 struct module *ip_conntrack_h323 = THIS_MODULE;
40 #define DEBUGP(format, args...)
43 /* FIXME: This should be in userspace. Later. */
44 static int h245_help(struct sk_buff *skb,
45 struct ip_conntrack *ct,
46 enum ip_conntrack_info ctinfo)
48 struct iphdr *iph = skb->nh.iph;
49 struct tcphdr _tcph, *tcph;
51 unsigned char *data_limit;
52 unsigned dataoff, datalen;
53 int dir = CTINFO2DIR(ctinfo);
54 struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
55 struct ip_conntrack_expect *exp;
56 struct ip_ct_h225_expect *exp_info;
62 /* Until there's been traffic both ways, don't look in packets. */
63 if (ctinfo != IP_CT_ESTABLISHED
64 && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
65 DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
69 tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4,
70 sizeof(_tcph), &_tcph);
74 DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
75 NIPQUAD(iph->saddr), ntohs(tcph->source),
76 NIPQUAD(iph->daddr), ntohs(tcph->dest));
78 dataoff = skb->nh.iph->ihl*4 + tcph->doff*4;
80 if (dataoff >= skb->len) {
81 DEBUGP("ct_h245_help: skblen = %u\n", skb->len);
84 datalen = skb->len - dataoff;
86 LOCK_BH(&h323_buffer_lock);
87 data = skb_header_pointer(skb, dataoff,
88 datalen, h323_buffer);
91 data_limit = data + datalen - 6;
94 for (i = 0; data <= data_limit; data++, i++) {
95 data_ip = *((u_int32_t *)data);
96 if (data_ip == iph->saddr) {
97 data_port = *((u_int16_t *)(data + 4));
99 /* update the H.225 info */
100 DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
101 NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
102 NIPQUAD(iph->saddr), ntohs(data_port));
104 exp = ip_conntrack_expect_alloc();
110 exp_info = &exp->help.exp_h225_info;
112 LOCK_BH(&ip_h323_lock);
113 info->is_h225 = H225_PORT + 1;
114 exp_info->port = data_port;
116 exp_info->offset = i;
118 exp->seq = ntohl(tcph->seq) + i;
120 exp->tuple = ((struct ip_conntrack_tuple)
121 { { ct->tuplehash[!dir].tuple.src.ip,
124 { .tcp = { data_port } },
126 exp->mask = ((struct ip_conntrack_tuple)
127 { { 0xFFFFFFFF, { 0 } },
128 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
130 exp->expectfn = NULL;
132 /* Ignore failure; should only happen with NAT */
133 ip_conntrack_expect_related(exp, ct);
135 UNLOCK_BH(&ip_h323_lock);
141 UNLOCK_BH(&h323_buffer_lock);
145 /* H.245 helper is not registered! */
146 static struct ip_conntrack_helper h245 = {
148 .flags = IP_CT_HELPER_F_REUSE_EXPECT,
151 .tuple = { .dst = { .protonum = IPPROTO_TCP } },
152 .mask = { .src = { .u = { 0xFFFF } },
153 .dst = { .protonum = 0xFFFF } },
157 static int h225_expect(struct ip_conntrack *ct)
159 WRITE_LOCK(&ip_conntrack_lock);
161 DEBUGP("h225_expect: helper for %p added\n", ct);
162 WRITE_UNLOCK(&ip_conntrack_lock);
164 return NF_ACCEPT; /* unused */
167 /* FIXME: This should be in userspace. Later. */
168 static int h225_help(struct sk_buff *skb,
169 struct ip_conntrack *ct,
170 enum ip_conntrack_info ctinfo)
172 struct iphdr *iph = skb->nh.iph;
173 struct tcphdr _tcph, *tcph;
175 unsigned char *data_limit;
176 unsigned dataoff, datalen;
177 int dir = CTINFO2DIR(ctinfo);
178 struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
179 struct ip_conntrack_expect *exp;
180 struct ip_ct_h225_expect *exp_info;
186 /* Until there's been traffic both ways, don't look in packets. */
187 if (ctinfo != IP_CT_ESTABLISHED
188 && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
189 DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
193 tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4,
194 sizeof(_tcph), &_tcph);
198 DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
199 NIPQUAD(iph->saddr), ntohs(tcph->source),
200 NIPQUAD(iph->daddr), ntohs(tcph->dest));
202 dataoff = skb->nh.iph->ihl*4 + tcph->doff*4;
204 if (dataoff >= skb->len) {
205 DEBUGP("ct_h225_help: skblen = %u\n", skb->len);
208 datalen = skb->len - dataoff;
210 LOCK_BH(&h323_buffer_lock);
211 data = skb_header_pointer(skb, dataoff,
212 datalen, h323_buffer);
213 BUG_ON(data == NULL);
215 data_limit = data + datalen - 6;
218 for (i = 0; data <= data_limit; data++, i++) {
219 data_ip = *((u_int32_t *)data);
220 if (data_ip == iph->saddr) {
221 data_port = *((u_int16_t *)(data + 4));
222 if (data_port == tcph->source) {
224 DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
225 NIPQUAD(iph->saddr));
226 /* Update the H.225 info so that NAT can mangle the address/port
227 even when we have no expected connection! */
228 #ifdef CONFIG_IP_NF_NAT_NEEDED
229 LOCK_BH(&ip_h323_lock);
231 info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
232 info->offset[IP_CT_DIR_ORIGINAL] = i;
233 UNLOCK_BH(&ip_h323_lock);
236 /* update the H.225 info */
237 exp = ip_conntrack_expect_alloc();
243 exp_info = &exp->help.exp_h225_info;
245 LOCK_BH(&ip_h323_lock);
246 info->is_h225 = H225_PORT;
247 exp_info->port = data_port;
249 exp_info->offset = i;
251 exp->seq = ntohl(tcph->seq) + i;
253 exp->tuple = ((struct ip_conntrack_tuple)
254 { { ct->tuplehash[!dir].tuple.src.ip,
257 { .tcp = { data_port } },
259 exp->mask = ((struct ip_conntrack_tuple)
260 { { 0xFFFFFFFF, { 0 } },
261 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
263 exp->expectfn = h225_expect;
266 ip_conntrack_expect_related(exp, ct);
268 DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
269 NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
270 NIPQUAD(iph->saddr), ntohs(data_port));
272 UNLOCK_BH(&ip_h323_lock);
274 #ifdef CONFIG_IP_NF_NAT_NEEDED
275 } else if (data_ip == iph->daddr) {
276 data_port = *((u_int16_t *)(data + 4));
277 if (data_port == tcph->dest) {
279 DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
280 NIPQUAD(iph->daddr));
281 /* Update the H.225 info so that NAT can mangle the address/port
282 even when we have no expected connection! */
283 LOCK_BH(&ip_h323_lock);
285 info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
286 info->offset[IP_CT_DIR_REPLY] = i;
287 UNLOCK_BH(&ip_h323_lock);
295 UNLOCK_BH(&h323_buffer_lock);
299 static struct ip_conntrack_helper h225 = {
301 .flags = IP_CT_HELPER_F_REUSE_EXPECT,
305 .tuple = { .src = { .ip = 0,
306 .u = { .tcp = { .port =
307 __constant_htons(H225_PORT) } }
311 .protonum = IPPROTO_TCP
314 .mask = { .src = { .ip = 0,
315 .u = { .tcp = { .port = 0xffff } }
325 static int __init init(void)
327 printk("ip_conntrack_h323: init \n");
328 return ip_conntrack_helper_register(&h225);
331 static void __exit fini(void)
333 /* Unregister H.225 helper */
334 ip_conntrack_helper_unregister(&h225);
337 EXPORT_SYMBOL(ip_h323_lock);
339 PROVIDES_CONNTRACK(h225);
340 PROVIDES_CONNTRACK(h245);