2 * H.323 'brute force' extension for H.323 connection tracking.
3 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5 * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
6 * (http://www.coritel.it/projects/sofia/nat/)
7 * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
8 * the unregistered helpers to the conntrack entries.
12 #include <linux/module.h>
13 #include <linux/netfilter.h>
15 #include <net/checksum.h>
18 #include <linux/netfilter_ipv4/lockhelp.h>
19 #include <linux/netfilter_ipv4/ip_conntrack.h>
20 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
21 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
22 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
23 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
25 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
26 MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
27 MODULE_LICENSE("GPL");
29 DECLARE_LOCK(ip_h323_lock);
30 struct module *ip_conntrack_h323 = THIS_MODULE;
35 #define DEBUGP(format, args...)
38 /* FIXME: This should be in userspace. Later. */
39 static int h245_help(struct sk_buff *skb,
40 struct ip_conntrack *ct,
41 enum ip_conntrack_info ctinfo)
43 struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl * 4;
44 unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
45 unsigned char *data_limit;
46 u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
47 u_int32_t datalen = tcplen - tcph->doff * 4;
48 int dir = CTINFO2DIR(ctinfo);
49 struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
50 struct ip_conntrack_expect expect, *exp = &expect;
51 struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
56 DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
57 NIPQUAD(iph->saddr), ntohs(tcph->source),
58 NIPQUAD(iph->daddr), ntohs(tcph->dest));
60 /* Can't track connections formed before we registered */
64 /* Until there's been traffic both ways, don't look in packets. */
65 if (ctinfo != IP_CT_ESTABLISHED
66 && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
67 DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
71 /* Not whole TCP header or too short packet? */
72 if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
73 DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
77 /* Checksum invalid? Ignore. */
78 /* FIXME: Source route IP option packets --RR */
79 if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr,
80 csum_partial((char *)tcph, tcplen, 0))) {
81 DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
82 tcph, tcplen, NIPQUAD(skb->nh.iph->saddr),
83 NIPQUAD(skb->nh.iph->daddr));
87 data_limit = (unsigned char *) data + datalen;
90 for (i = 0; data < (data_limit - 5); data++, i++) {
91 data_ip = *((u_int32_t *)data);
92 if (data_ip == skb->nh.iph->saddr) {
93 data_port = *((u_int16_t *)(data + 4));
94 memset(&expect, 0, sizeof(expect));
95 /* update the H.225 info */
96 DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
97 NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
98 NIPQUAD(skb->nh.iph->saddr), ntohs(data_port));
99 LOCK_BH(&ip_h323_lock);
100 info->is_h225 = H225_PORT + 1;
101 exp_info->port = data_port;
103 exp_info->offset = i;
105 exp->seq = ntohl(tcph->seq) + i;
107 exp->tuple = ((struct ip_conntrack_tuple)
108 { { ct->tuplehash[!dir].tuple.src.ip,
111 { .tcp = { data_port } },
113 exp->mask = ((struct ip_conntrack_tuple)
114 { { 0xFFFFFFFF, { 0 } },
115 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
117 exp->expectfn = NULL;
119 /* Ignore failure; should only happen with NAT */
120 ip_conntrack_expect_related(exp, ct);
122 UNLOCK_BH(&ip_h323_lock);
130 /* H.245 helper is not registered! */
131 static struct ip_conntrack_helper h245 =
133 name : "H.245", /* name */
134 flags: IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
135 me: THIS_MODULE, /* module */
136 max_expected: 8, /* max_ expected */
137 timeout: 240, /* timeout */
138 tuple: { { 0, { 0 } }, /* tuple */
139 { 0, { 0 }, IPPROTO_TCP } },
140 mask: { { 0, { 0xFFFF } }, /* mask */
141 { 0, { 0 }, 0xFFFF } },
142 h245_help /* helper */
145 static int h225_expect(struct ip_conntrack *ct)
147 WRITE_LOCK(&ip_conntrack_lock);
149 DEBUGP("h225_expect: helper for %p added\n", ct);
150 WRITE_UNLOCK(&ip_conntrack_lock);
152 return NF_ACCEPT; /* unused */
155 /* FIXME: This should be in userspace. Later. */
156 static int h225_help(struct sk_buff *skb,
157 struct ip_conntrack *ct,
158 enum ip_conntrack_info ctinfo)
160 struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl * 4;
161 unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
162 unsigned char *data_limit;
163 u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
164 u_int32_t datalen = tcplen - tcph->doff * 4;
165 int dir = CTINFO2DIR(ctinfo);
166 struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
167 struct ip_conntrack_expect expect, *exp = &expect;
168 struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
173 DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
174 NIPQUAD(skb->nh.iph->saddr), ntohs(tcph->source),
175 NIPQUAD(skb->nh.iph->daddr), ntohs(tcph->dest));
177 /* Can't track connections formed before we registered */
181 /* Until there's been traffic both ways, don't look in packets. */
182 if (ctinfo != IP_CT_ESTABLISHED
183 && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
184 DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
188 /* Not whole TCP header or too short packet? */
189 if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
190 DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
194 /* Checksum invalid? Ignore. */
195 /* FIXME: Source route IP option packets --RR */
196 if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr,
197 csum_partial((char *)tcph, tcplen, 0))) {
198 DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
199 tcph, tcplen, NIPQUAD(skb->nh.iph->saddr),
200 NIPQUAD(skb->nh.iph->daddr));
204 data_limit = (unsigned char *) data + datalen;
207 for (i = 0; data < (data_limit - 5); data++, i++) {
208 data_ip = *((u_int32_t *)data);
209 if (data_ip == skb->nh.iph->saddr) {
210 data_port = *((u_int16_t *)(data + 4));
211 if (data_port == tcph->source) {
213 DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
214 NIPQUAD(skb->nh.iph->saddr));
215 /* Update the H.225 info so that NAT can mangle the address/port
216 even when we have no expected connection! */
217 #ifdef CONFIG_IP_NF_NAT_NEEDED
218 LOCK_BH(&ip_h323_lock);
220 info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
221 info->offset[IP_CT_DIR_ORIGINAL] = i;
222 UNLOCK_BH(&ip_h323_lock);
225 memset(&expect, 0, sizeof(expect));
227 /* update the H.225 info */
228 LOCK_BH(&ip_h323_lock);
229 info->is_h225 = H225_PORT;
230 exp_info->port = data_port;
232 exp_info->offset = i;
234 exp->seq = ntohl(tcph->seq) + i;
236 exp->tuple = ((struct ip_conntrack_tuple)
237 { { ct->tuplehash[!dir].tuple.src.ip,
240 { .tcp = { data_port } },
242 exp->mask = ((struct ip_conntrack_tuple)
243 { { 0xFFFFFFFF, { 0 } },
244 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
246 exp->expectfn = h225_expect;
249 ip_conntrack_expect_related(exp, ct);
251 DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
252 NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
253 NIPQUAD(skb->nh.iph->saddr), ntohs(data_port));
255 UNLOCK_BH(&ip_h323_lock);
257 #ifdef CONFIG_IP_NF_NAT_NEEDED
258 } else if (data_ip == skb->nh.iph->daddr) {
259 data_port = *((u_int16_t *)(data + 4));
260 if (data_port == tcph->dest) {
262 DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
263 NIPQUAD(skb->nh.iph->daddr));
264 /* Update the H.225 info so that NAT can mangle the address/port
265 even when we have no expected connection! */
266 LOCK_BH(&ip_h323_lock);
268 info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
269 info->offset[IP_CT_DIR_REPLY] = i;
270 UNLOCK_BH(&ip_h323_lock);
280 static struct ip_conntrack_helper h225 =
283 IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
284 THIS_MODULE, /* module */
285 2, /* max_expected */
287 { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
288 { 0, { 0 }, IPPROTO_TCP } },
289 { { 0, { 0xFFFF } }, /* mask */
290 { 0, { 0 }, 0xFFFF } },
291 h225_help /* helper */
294 static int __init init(void)
296 return ip_conntrack_helper_register(&h225);
299 static void __exit fini(void)
301 /* Unregister H.225 helper */
302 ip_conntrack_helper_unregister(&h225);
305 EXPORT_SYMBOL(ip_h323_lock);