2 * H.323 'brute force' extension for NAT alteration.
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.html)
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_nat.h>
21 #include <linux/netfilter_ipv4/ip_nat_helper.h>
22 #include <linux/netfilter_ipv4/ip_nat_rule.h>
23 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
24 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
25 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
27 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
28 MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
29 MODULE_LICENSE("GPL");
31 DECLARE_LOCK_EXTERN(ip_h323_lock);
32 struct module *ip_nat_h323 = THIS_MODULE;
37 #define DEBUGP(format, args...)
40 /* FIXME: Time out? --RR */
43 h225_nat_expected(struct sk_buff **pskb,
45 struct ip_conntrack *ct,
46 struct ip_nat_info *info);
48 static unsigned int h225_nat_help(struct ip_conntrack *ct,
49 struct ip_conntrack_expect *exp,
50 struct ip_nat_info *info,
51 enum ip_conntrack_info ctinfo,
53 struct sk_buff **pskb);
55 static struct ip_nat_helper h245 = {
56 .list = { NULL, NULL },
60 .tuple = { .src = { .ip = 0,
61 .u = { .tcp = { .port = 0 } }
65 .protonum = IPPROTO_TCP
68 .mask = { .src = { .ip = 0,
69 .u = { .tcp = { .port = 0xffff } }
76 .help = h225_nat_help,
77 .expect = h225_nat_expected
81 h225_nat_expected(struct sk_buff **pskb,
83 struct ip_conntrack *ct,
84 struct ip_nat_info *info)
86 struct ip_nat_multi_range mr;
87 u_int32_t newdstip, newsrcip, newip;
89 struct ip_ct_h225_expect *exp_info;
90 struct ip_ct_h225_master *master_info;
91 struct ip_conntrack *master = master_ct(ct);
92 unsigned int is_h225, ret;
97 IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
99 DEBUGP("h225_nat_expected: We have a connection!\n");
100 master_info = &ct->master->expectant->help.ct_h225_info;
101 exp_info = &ct->master->help.exp_h225_info;
103 LOCK_BH(&ip_h323_lock);
106 DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
107 DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
108 DEBUGP("conntrack: ");
109 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
110 if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
111 /* Make connection go to the client. */
112 newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
113 newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
114 DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
115 NIPQUAD(newsrcip), NIPQUAD(newdstip));
117 /* Make the connection go to the server */
118 newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
119 newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
120 DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
121 NIPQUAD(newsrcip), NIPQUAD(newdstip));
123 port = exp_info->port;
124 is_h225 = master_info->is_h225 == H225_PORT;
125 UNLOCK_BH(&ip_h323_lock);
127 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
132 DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
134 /* We don't want to manip the per-protocol, just the IPs... */
136 mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
137 mr.range[0].min_ip = mr.range[0].max_ip = newip;
139 /* ... unless we're doing a MANIP_DST, in which case, make
140 sure we map to the correct port */
141 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
142 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
143 mr.range[0].min = mr.range[0].max
144 = ((union ip_conntrack_manip_proto)
145 { .tcp = { port } });
148 ret = ip_nat_setup_info(ct, &mr, hooknum);
151 DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
152 /* NAT expectfn called with ip_nat_lock write-locked */
153 info->helper = &h245;
158 static int h323_signal_address_fixup(struct ip_conntrack *ct,
159 struct sk_buff **pskb,
160 enum ip_conntrack_info ctinfo)
162 struct iphdr *iph = (*pskb)->nh.iph;
163 struct tcphdr _tcph, *tcph;
164 u_int32_t tcplen, datalen;
165 struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
169 } __attribute__ ((__packed__)) newdata;
173 tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
177 tcplen = (*pskb)->len - iph->ihl * 4;
178 datalen = tcplen - tcph->doff * 4;
180 MUST_BE_LOCKED(&ip_h323_lock);
182 DEBUGP("h323_signal_address_fixup: %s %s\n",
183 between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
185 between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
187 if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
188 || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
191 DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
192 info->offset[IP_CT_DIR_ORIGINAL],
193 info->offset[IP_CT_DIR_REPLY],
195 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
196 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
198 for (i = 0; i < IP_CT_DIR_MAX; i++) {
199 DEBUGP("h323_signal_address_fixup: %s %s\n",
200 info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
201 i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
202 if (!between(info->seq[i], ntohl(tcph->seq),
203 ntohl(tcph->seq) + datalen))
205 if (!between(info->seq[i] + 6, ntohl(tcph->seq),
206 ntohl(tcph->seq) + datalen)) {
207 /* Partial retransmisison. It's a cracker being funky. */
208 if (net_ratelimit()) {
209 printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
212 ntohl(tcph->seq) + datalen);
217 /* Change address inside packet to match way we're mapping
219 if (i == IP_CT_DIR_ORIGINAL) {
220 newdata.ip = ct->tuplehash[!info->dir].tuple.dst.ip;
221 newdata.port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
223 newdata.ip = ct->tuplehash[!info->dir].tuple.src.ip;
224 newdata.port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
227 /* Modify the packet */
228 ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
229 info->seq[i] - ntohl(tcph->seq),
231 (const char*)&newdata, sizeof(newdata));
239 static int h323_data_fixup(struct ip_ct_h225_expect *info,
240 struct ip_conntrack *ct,
241 struct sk_buff **pskb,
242 enum ip_conntrack_info ctinfo,
243 struct ip_conntrack_expect *expect)
248 } __attribute__ ((__packed__)) newdata;
249 struct ip_conntrack_tuple newtuple;
250 struct iphdr *iph = (*pskb)->nh.iph;
251 struct tcphdr _tcph, *tcph;
253 struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
257 tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
261 tcplen = (*pskb)->len - iph->ihl * 4;
263 MUST_BE_LOCKED(&ip_h323_lock);
264 DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
265 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
266 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
268 if (!between(expect->seq + 6, ntohl(tcph->seq),
269 ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
270 /* Partial retransmisison. It's a cracker being funky. */
271 if (net_ratelimit()) {
272 printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
275 ntohl(tcph->seq) + tcplen - tcph->doff * 4);
280 /* Change address inside packet to match way we're mapping
282 if (info->dir == IP_CT_DIR_REPLY) {
283 /* Must be where client thinks server is */
284 newdata.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
285 /* Expect something from client->server */
286 newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
287 newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
289 /* Must be where server thinks client is */
290 newdata.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
291 /* Expect something from server->client */
292 newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
293 newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
296 is_h225 = (master_info->is_h225 == H225_PORT);
299 newtuple.dst.protonum = IPPROTO_TCP;
300 newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
302 newtuple.dst.protonum = IPPROTO_UDP;
303 newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
306 /* Try to get same port: if not, try to change it. */
307 for (newdata.port = ntohs(info->port); newdata.port != 0; newdata.port++) {
309 newtuple.dst.u.tcp.port = htons(newdata.port);
311 newtuple.dst.u.udp.port = htons(newdata.port);
313 if (ip_conntrack_change_expect(expect, &newtuple) == 0)
316 if (newdata.port == 0) {
317 DEBUGP("h323_data_fixup: no free port found!\n");
321 newdata.port = htons(newdata.port);
323 /* Modify the packet */
324 ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
325 expect->seq - ntohl(tcph->seq),
327 (const char*)&newdata, sizeof(newdata));
334 static unsigned int h225_nat_help(struct ip_conntrack *ct,
335 struct ip_conntrack_expect *exp,
336 struct ip_nat_info *info,
337 enum ip_conntrack_info ctinfo,
338 unsigned int hooknum,
339 struct sk_buff **pskb)
342 struct ip_ct_h225_expect *exp_info;
344 /* Only mangle things once: original direction in POST_ROUTING
345 and reply direction on PRE_ROUTING. */
346 dir = CTINFO2DIR(ctinfo);
347 DEBUGP("nat_h323: dir %s at hook %s\n",
348 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
349 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
350 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
351 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
352 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
353 || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
354 DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
355 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
356 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
357 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
358 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
363 LOCK_BH(&ip_h323_lock);
364 if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
365 UNLOCK_BH(&ip_h323_lock);
368 UNLOCK_BH(&ip_h323_lock);
372 exp_info = &exp->help.exp_h225_info;
374 LOCK_BH(&ip_h323_lock);
375 if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
376 UNLOCK_BH(&ip_h323_lock);
379 UNLOCK_BH(&ip_h323_lock);
384 static struct ip_nat_helper h225 = {
385 .list = { NULL, NULL },
387 .flags = IP_NAT_HELPER_F_ALWAYS,
389 .tuple = { .src = { .ip = 0,
390 .u = { .tcp = { .port =
391 __constant_htons(H225_PORT) } }
395 .protonum = IPPROTO_TCP
398 .mask = { .src = { .ip = 0,
399 .u = { .tcp = { .port = 0xffff } }
406 .help = h225_nat_help,
407 .expect = h225_nat_expected
410 static int __init init(void)
414 printk("ip_nat_h323: initialize the module!\n");
415 ret = ip_nat_helper_register(&h225);
418 printk("ip_nat_h323: cannot initialize the module!\n");
423 static void __exit fini(void)
425 ip_nat_helper_unregister(&h225);
428 NEEDS_CONNTRACK(h225);
429 NEEDS_CONNTRACK(h245);