1/* 2 * H.323 'brute force' extension for NAT alteration. 3 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 4 * 5 * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. 6 * (http://www.coritel.it/projects/sofia/nat.html) 7 * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' 8 * the unregistered helpers to the conntrack entries. 9 */ 10 11 12#include <linux/module.h> 13#include <linux/netfilter.h> 14#include <linux/ip.h> 15#include <net/checksum.h> 16#include <net/tcp.h> 17 18#include <linux/netfilter_ipv4/lockhelp.h> 19#include <linux/netfilter_ipv4/ip_nat.h> 20#include <linux/netfilter_ipv4/ip_nat_helper.h> 21#include <linux/netfilter_ipv4/ip_nat_rule.h> 22#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> 23#include <linux/netfilter_ipv4/ip_conntrack_helper.h> 24#include <linux/netfilter_ipv4/ip_conntrack_h323.h> 25 26MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 27MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); 28MODULE_LICENSE("GPL"); 29 30DECLARE_LOCK_EXTERN(ip_h323_lock); 31struct module *ip_nat_h323 = THIS_MODULE; 32 33#define DEBUGP(format, args...) 34 35 36static unsigned int 37h225_nat_expected(struct sk_buff **pskb, 38 unsigned int hooknum, 39 struct ip_conntrack *ct, 40 struct ip_nat_info *info); 41 42static unsigned int h225_nat_help(struct ip_conntrack *ct, 43 struct ip_conntrack_expect *exp, 44 struct ip_nat_info *info, 45 enum ip_conntrack_info ctinfo, 46 unsigned int hooknum, 47 struct sk_buff **pskb); 48 49static struct ip_nat_helper h245 = 50 { { NULL, NULL }, 51 "H.245", /* name */ 52 0, /* flags */ 53 NULL, /* module */ 54 { { 0, { 0 } }, /* tuple */ 55 { 0, { 0 }, IPPROTO_TCP } }, 56 { { 0, { 0xFFFF } }, /* mask */ 57 { 0, { 0 }, 0xFFFF } }, 58 h225_nat_help, /* helper */ 59 h225_nat_expected /* expectfn */ 60 }; 61 62static unsigned int 63h225_nat_expected(struct sk_buff **pskb, 64 unsigned int hooknum, 65 struct ip_conntrack *ct, 66 struct ip_nat_info *info) 67{ 68 struct ip_nat_multi_range mr; 69 u_int32_t newdstip, newsrcip, newip; 70 u_int16_t port; 71 struct ip_ct_h225_expect *exp_info; 72 struct ip_ct_h225_master *master_info; 73 struct ip_conntrack *master = master_ct(ct); 74 unsigned int is_h225, ret; 75 76 IP_NF_ASSERT(info); 77 IP_NF_ASSERT(master); 78 79 IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); 80 81 DEBUGP("h225_nat_expected: We have a connection!\n"); 82 master_info = &ct->master->expectant->help.ct_h225_info; 83 exp_info = &ct->master->help.exp_h225_info; 84 85 LOCK_BH(&ip_h323_lock); 86 87 DEBUGP("master: "); 88 DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 89 DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); 90 DEBUGP("conntrack: "); 91 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 92 if (exp_info->dir == IP_CT_DIR_ORIGINAL) { 93 /* Make connection go to the client. */ 94 newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; 95 newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; 96 DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", 97 NIPQUAD(newsrcip), NIPQUAD(newdstip)); 98 } else { 99 /* Make the connection go to the server */ 100 newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; 101 newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; 102 DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", 103 NIPQUAD(newsrcip), NIPQUAD(newdstip)); 104 } 105 port = exp_info->port; 106 is_h225 = master_info->is_h225 == H225_PORT; 107 UNLOCK_BH(&ip_h323_lock); 108 109 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) 110 newip = newsrcip; 111 else 112 newip = newdstip; 113 114 DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); 115 116 mr.rangesize = 1; 117 /* We don't want to manip the per-protocol, just the IPs... */ 118 mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; 119 mr.range[0].min_ip = mr.range[0].max_ip = newip; 120 121 /* ... unless we're doing a MANIP_DST, in which case, make 122 sure we map to the correct port */ 123 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { 124 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 125 mr.range[0].min = mr.range[0].max 126 = ((union ip_conntrack_manip_proto) 127 { port }); 128 } 129 130 ret = ip_nat_setup_info(ct, &mr, hooknum); 131 132 if (is_h225) { 133 DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); 134 /* NAT expectfn called with ip_nat_lock write-locked */ 135 info->helper = &h245; 136 } 137 return ret; 138} 139 140static int h323_signal_address_fixup(struct ip_conntrack *ct, 141 struct sk_buff **pskb, 142 enum ip_conntrack_info ctinfo) 143{ 144 struct iphdr *iph = (*pskb)->nh.iph; 145 struct tcphdr *tcph = (void *)iph + iph->ihl*4; 146 unsigned char *data; 147 u_int32_t tcplen = (*pskb)->len - iph->ihl*4; 148 u_int32_t datalen = tcplen - tcph->doff*4; 149 struct ip_ct_h225_master *info = &ct->help.ct_h225_info; 150 u_int32_t newip; 151 u_int16_t port; 152 u_int8_t buffer[6]; 153 int i; 154 155 MUST_BE_LOCKED(&ip_h323_lock); 156 157 DEBUGP("h323_signal_address_fixup: %s %s\n", 158 between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) 159 ? "yes" : "no", 160 between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) 161 ? "yes" : "no"); 162 if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) 163 || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) 164 return 1; 165 166 DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", 167 info->offset[IP_CT_DIR_ORIGINAL], 168 info->offset[IP_CT_DIR_REPLY], 169 tcplen); 170 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 171 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 172 173 for (i = 0; i < IP_CT_DIR_MAX; i++) { 174 DEBUGP("h323_signal_address_fixup: %s %s\n", 175 info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", 176 i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); 177 if (!between(info->seq[i], ntohl(tcph->seq), 178 ntohl(tcph->seq) + datalen)) 179 continue; 180 if (!between(info->seq[i] + 6, ntohl(tcph->seq), 181 ntohl(tcph->seq) + datalen)) { 182 /* Partial retransmisison. It's a cracker being funky. */ 183 if (net_ratelimit()) { 184 printk("H.323_NAT: partial packet %u/6 in %u/%u\n", 185 info->seq[i], 186 ntohl(tcph->seq), 187 ntohl(tcph->seq) + datalen); 188 } 189 return 0; 190 } 191 192 /* Change address inside packet to match way we're mapping 193 this connection. */ 194 if (i == IP_CT_DIR_ORIGINAL) { 195 newip = ct->tuplehash[!info->dir].tuple.dst.ip; 196 port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; 197 } else { 198 newip = ct->tuplehash[!info->dir].tuple.src.ip; 199 port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; 200 } 201 202 data = (char *) tcph + tcph->doff * 4 + info->offset[i]; 203 204 DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", 205 i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", 206 data[0], data[1], data[2], data[3], 207 (data[4] << 8 | data[5])); 208 209 /* Modify the packet */ 210 memcpy(buffer, &newip, 4); 211 memcpy(buffer + 4, &port, 2); 212 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], 213 6, buffer, 6)) 214 return 0; 215 216 DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", 217 i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", 218 data[0], data[1], data[2], data[3], 219 (data[4] << 8 | data[5])); 220 } 221 222 return 1; 223} 224 225static int h323_data_fixup(struct ip_ct_h225_expect *info, 226 struct ip_conntrack *ct, 227 struct sk_buff **pskb, 228 enum ip_conntrack_info ctinfo, 229 struct ip_conntrack_expect *expect) 230{ 231 u_int32_t newip; 232 u_int16_t port; 233 u_int8_t buffer[6]; 234 struct ip_conntrack_tuple newtuple; 235 struct iphdr *iph = (*pskb)->nh.iph; 236 struct tcphdr *tcph = (void *)iph + iph->ihl*4; 237 unsigned char *data; 238 u_int32_t tcplen = (*pskb)->len - iph->ihl*4; 239 struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; 240 int is_h225; 241 242 MUST_BE_LOCKED(&ip_h323_lock); 243 DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); 244 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 245 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 246 247 if (!between(expect->seq + 6, ntohl(tcph->seq), 248 ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { 249 /* Partial retransmisison. It's a cracker being funky. */ 250 if (net_ratelimit()) { 251 printk("H.323_NAT: partial packet %u/6 in %u/%u\n", 252 expect->seq, 253 ntohl(tcph->seq), 254 ntohl(tcph->seq) + tcplen - tcph->doff * 4); 255 } 256 return 0; 257 } 258 259 /* Change address inside packet to match way we're mapping 260 this connection. */ 261 if (info->dir == IP_CT_DIR_REPLY) { 262 /* Must be where client thinks server is */ 263 newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; 264 /* Expect something from client->server */ 265 newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; 266 newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; 267 } else { 268 /* Must be where server thinks client is */ 269 newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; 270 /* Expect something from server->client */ 271 newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; 272 newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; 273 } 274 275 is_h225 = (master_info->is_h225 == H225_PORT); 276 277 if (is_h225) { 278 newtuple.dst.protonum = IPPROTO_TCP; 279 newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; 280 } else { 281 newtuple.dst.protonum = IPPROTO_UDP; 282 newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; 283 } 284 285 /* Try to get same port: if not, try to change it. */ 286 for (port = ntohs(info->port); port != 0; port++) { 287 if (is_h225) 288 newtuple.dst.u.tcp.port = htons(port); 289 else 290 newtuple.dst.u.udp.port = htons(port); 291 292 if (ip_conntrack_change_expect(expect, &newtuple) == 0) 293 break; 294 } 295 if (port == 0) { 296 DEBUGP("h323_data_fixup: no free port found!\n"); 297 return 0; 298 } 299 300 port = htons(port); 301 302 data = (char *) tcph + tcph->doff * 4 + info->offset; 303 304 DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", 305 data[0], data[1], data[2], data[3], 306 (data[4] << 8 | data[5])); 307 308 /* Modify the packet */ 309 memcpy(buffer, &newip, 4); 310 memcpy(buffer + 4, &port, 2); 311 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, 312 6, buffer, 6)) 313 return 0; 314 315 DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", 316 data[0], data[1], data[2], data[3], 317 (data[4] << 8 | data[5])); 318 319 return 1; 320} 321 322static unsigned int h225_nat_help(struct ip_conntrack *ct, 323 struct ip_conntrack_expect *exp, 324 struct ip_nat_info *info, 325 enum ip_conntrack_info ctinfo, 326 unsigned int hooknum, 327 struct sk_buff **pskb) 328{ 329 int dir; 330 struct ip_ct_h225_expect *exp_info; 331 332 /* Only mangle things once: original direction in POST_ROUTING 333 and reply direction on PRE_ROUTING. */ 334 dir = CTINFO2DIR(ctinfo); 335 DEBUGP("nat_h323: dir %s at hook %s\n", 336 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", 337 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" 338 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" 339 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); 340 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) 341 || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { 342 DEBUGP("nat_h323: Not touching dir %s at hook %s\n", 343 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", 344 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" 345 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" 346 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); 347 return NF_ACCEPT; 348 } 349 350 if (!exp) { 351 LOCK_BH(&ip_h323_lock); 352 if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { 353 UNLOCK_BH(&ip_h323_lock); 354 return NF_DROP; 355 } 356 UNLOCK_BH(&ip_h323_lock); 357 return NF_ACCEPT; 358 } 359 360 exp_info = &exp->help.exp_h225_info; 361 362 LOCK_BH(&ip_h323_lock); 363 if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { 364 UNLOCK_BH(&ip_h323_lock); 365 return NF_DROP; 366 } 367 UNLOCK_BH(&ip_h323_lock); 368 369 return NF_ACCEPT; 370} 371 372static struct ip_nat_helper h225 = 373 { { NULL, NULL }, 374 "H.225", /* name */ 375 IP_NAT_HELPER_F_ALWAYS, /* flags */ 376 THIS_MODULE, /* module */ 377 { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ 378 { 0, { 0 }, IPPROTO_TCP } }, 379 { { 0, { 0xFFFF } }, /* mask */ 380 { 0, { 0 }, 0xFFFF } }, 381 h225_nat_help, /* helper */ 382 h225_nat_expected /* expectfn */ 383 }; 384 385static int __init init(void) 386{ 387 int ret; 388 389 ret = ip_nat_helper_register(&h225); 390 391 if (ret != 0) 392 printk("ip_nat_h323: cannot initialize the module!\n"); 393 394 return ret; 395} 396 397static void __exit fini(void) 398{ 399 ip_nat_helper_unregister(&h225); 400} 401 402module_init(init); 403module_exit(fini); 404