1 /* 2 * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved 3 * 4 * This source code has been published by QNX Software Systems Ltd. (QSSL). 5 * However, any use, reproduction, modification, distribution or transfer of 6 * this software, or any software which includes or is based upon any of this 7 * code, is only permitted under the terms of the QNX Open Community License 8 * version 1.0 (see licensing.qnx.com for details) or as otherwise expressly 9 * authorized by a written license agreement from QSSL. For more information, 10 * please email licensing@qnx.com. 11 * 12 * For more details, see QNX_OCL.txt provided with this distribution. 13 * 14 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 15 * Use is subject to license terms. 16 */ 17 18 /* 19 * Simple H.323 proxy 20 * 21 * by xtang@canada.com 22 * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org 23 */ 24 25 #if __FreeBSD_version >= 220000 && defined(_KERNEL) 26 # include <sys/fcntl.h> 27 # include <sys/filio.h> 28 #else 29 # ifndef linux 30 # include <sys/ioctl.h> 31 # endif 32 #endif 33 34 #define IPF_H323_PROXY 35 36 typedef struct ifs_h323pxy { 37 frentry_t h323_fr; 38 int h323_proxy_init; 39 } ifs_h323pxy_t; 40 41 int ippr_h323_init __P((void **, ipf_stack_t *)); 42 void ippr_h323_fini __P((void **, ipf_stack_t *)); 43 int ippr_h323_new __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 44 void ippr_h323_del __P((ap_session_t *, void *, ipf_stack_t *)); 45 int ippr_h323_out __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 46 int ippr_h323_in __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 47 48 int ippr_h245_new __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 49 int ippr_h245_out __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 50 int ippr_h245_in __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 51 52 static int find_port __P((int, caddr_t, int datlen, int *, u_short *)); 53 54 55 static int find_port(ipaddr, data, datlen, off, port) 56 int ipaddr; 57 caddr_t data; 58 int datlen, *off; 59 unsigned short *port; 60 { 61 u_32_t addr, netaddr; 62 u_char *dp; 63 int offset; 64 65 if (datlen < 6) 66 return -1; 67 68 *port = 0; 69 offset = *off; 70 dp = (u_char *)data; 71 netaddr = ntohl(ipaddr); 72 73 for (offset = 0; offset <= datlen - 6; offset++, dp++) { 74 addr = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3]; 75 if (netaddr == addr) 76 { 77 *port = (*(dp + 4) << 8) | *(dp + 5); 78 break; 79 } 80 } 81 *off = offset; 82 return (offset > datlen - 6) ? -1 : 0; 83 } 84 85 /* 86 * Initialize local structures. 87 */ 88 /*ARGSUSED*/ 89 int ippr_h323_init(private, ifs) 90 void **private; 91 ipf_stack_t *ifs; 92 { 93 ifs_h323pxy_t *ifsh323; 94 95 KMALLOC(ifsh323, ifs_h323pxy_t *); 96 if (ifsh323 == NULL) 97 return -1; 98 99 ifsh323->h323_fr.fr_ref = 1; 100 ifsh323->h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 101 MUTEX_INIT(&ifsh323->h323_fr.fr_lock, "H323 proxy rule lock"); 102 ifsh323->h323_proxy_init = 1; 103 104 *private = (void *)ifsh323; 105 106 return 0; 107 } 108 109 110 /*ARGSUSED*/ 111 void ippr_h323_fini(private, ifs) 112 void **private; 113 ipf_stack_t *ifs; 114 { 115 ifs_h323pxy_t *ifsh323 = *((ifs_h323pxy_t **)private); 116 117 if (ifsh323->h323_proxy_init == 1) { 118 MUTEX_DESTROY(&ifsh323->h323_fr.fr_lock); 119 ifsh323->h323_proxy_init = 0; 120 } 121 122 KFREE(ifsh323); 123 *private = NULL; 124 } 125 126 /*ARGSUSED*/ 127 int ippr_h323_new(fin, aps, nat, private) 128 fr_info_t *fin; 129 ap_session_t *aps; 130 nat_t *nat; 131 void *private; 132 { 133 fin = fin; /* LINT */ 134 nat = nat; /* LINT */ 135 136 aps->aps_data = NULL; 137 aps->aps_psiz = 0; 138 139 return 0; 140 } 141 142 /*ARGSUSED*/ 143 void ippr_h323_del(aps, private, ifs) 144 ap_session_t *aps; 145 void *private; 146 ipf_stack_t *ifs; 147 { 148 int i; 149 ipnat_t *ipn; 150 151 if (aps->aps_data) { 152 for (i = 0, ipn = aps->aps_data; 153 i < (aps->aps_psiz / sizeof(ipnat_t)); 154 i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn))) 155 { 156 /* 157 * Check the comment in ippr_h323_in() function, 158 * just above fr_nat_ioctl() call. 159 * We are lucky here because this function is not 160 * called with ipf_nat locked. 161 */ 162 if (fr_nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| 163 NAT_LOCKHELD|FWRITE, 0, NULL, ifs) == -1) { 164 /*EMPTY*/; 165 /* log the error */ 166 } 167 } 168 KFREES(aps->aps_data, aps->aps_psiz); 169 /* avoid double free */ 170 aps->aps_data = NULL; 171 aps->aps_psiz = 0; 172 } 173 return; 174 } 175 176 177 /*ARGSUSED*/ 178 int ippr_h323_in(fin, aps, nat, private) 179 fr_info_t *fin; 180 ap_session_t *aps; 181 nat_t *nat; 182 void *private; 183 { 184 int ipaddr, off, datlen; 185 unsigned short port; 186 caddr_t data; 187 tcphdr_t *tcp; 188 ip_t *ip; 189 ipf_stack_t *ifs = fin->fin_ifs; 190 191 ip = fin->fin_ip; 192 tcp = (tcphdr_t *)fin->fin_dp; 193 ipaddr = ip->ip_src.s_addr; 194 195 data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); 196 datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 197 if (find_port(ipaddr, data, datlen, &off, &port) == 0) { 198 ipnat_t *ipn; 199 char *newarray; 200 201 /* setup a nat rule to set a h245 proxy on tcp-port "port" 202 * it's like: 203 * map <if> <inter_ip>/<mask> -> <gate_ip>/<mask> proxy port <port> <port>/tcp 204 */ 205 KMALLOCS(newarray, char *, aps->aps_psiz + sizeof(*ipn)); 206 if (newarray == NULL) { 207 return -1; 208 } 209 ipn = (ipnat_t *)&newarray[aps->aps_psiz]; 210 bcopy((caddr_t)nat->nat_ptr, (caddr_t)ipn, sizeof(ipnat_t)); 211 (void) strncpy(ipn->in_plabel, "h245", APR_LABELLEN); 212 213 ipn->in_inip = nat->nat_inip.s_addr; 214 ipn->in_inmsk = 0xffffffff; 215 ipn->in_dport = htons(port); 216 /* 217 * we got a problem here. we need to call fr_nat_ioctl() to add 218 * the h245 proxy rule, but since we already hold (READ locked) 219 * the nat table rwlock (ipf_nat), if we go into fr_nat_ioctl(), 220 * it will try to WRITE lock it. This will causing dead lock 221 * on RTP. 222 * 223 * The quick & dirty solution here is release the read lock, 224 * call fr_nat_ioctl() and re-lock it. 225 * A (maybe better) solution is do a UPGRADE(), and instead 226 * of calling fr_nat_ioctl(), we add the nat rule ourself. 227 */ 228 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 229 if (fr_nat_ioctl((caddr_t)ipn, SIOCADNAT, 230 NAT_SYSSPACE|FWRITE, 0, NULL, ifs) == -1) { 231 READ_ENTER(&ifs->ifs_ipf_nat); 232 return -1; 233 } 234 READ_ENTER(&ifs->ifs_ipf_nat); 235 if (aps->aps_data != NULL && aps->aps_psiz > 0) { 236 bcopy(aps->aps_data, newarray, aps->aps_psiz); 237 KFREES(aps->aps_data, aps->aps_psiz); 238 } 239 aps->aps_data = newarray; 240 aps->aps_psiz += sizeof(*ipn); 241 } 242 return 0; 243 } 244 245 246 /*ARGSUSED*/ 247 int ippr_h245_new(fin, aps, nat, private) 248 fr_info_t *fin; 249 ap_session_t *aps; 250 nat_t *nat; 251 void *private; 252 { 253 fin = fin; /* LINT */ 254 nat = nat; /* LINT */ 255 256 aps->aps_data = NULL; 257 aps->aps_psiz = 0; 258 return 0; 259 } 260 261 262 /*ARGSUSED*/ 263 int ippr_h245_out(fin, aps, nat, private) 264 fr_info_t *fin; 265 ap_session_t *aps; 266 nat_t *nat; 267 void *private; 268 { 269 int ipaddr, off, datlen; 270 tcphdr_t *tcp; 271 caddr_t data; 272 u_short port; 273 ip_t *ip; 274 ipf_stack_t *ifs = fin->fin_ifs; 275 276 aps = aps; /* LINT */ 277 278 ip = fin->fin_ip; 279 tcp = (tcphdr_t *)fin->fin_dp; 280 ipaddr = nat->nat_inip.s_addr; 281 data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); 282 datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 283 if (find_port(ipaddr, data, datlen, &off, &port) == 0) { 284 fr_info_t fi; 285 nat_t *nat2; 286 287 /* port = htons(port); */ 288 nat2 = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, 289 ip->ip_src, ip->ip_dst); 290 if (nat2 == NULL) { 291 struct ip newip; 292 struct udphdr udp; 293 294 bcopy((caddr_t)ip, (caddr_t)&newip, sizeof(newip)); 295 newip.ip_len = fin->fin_hlen + sizeof(udp); 296 newip.ip_p = IPPROTO_UDP; 297 newip.ip_src = nat->nat_inip; 298 299 bzero((char *)&udp, sizeof(udp)); 300 udp.uh_sport = port; 301 302 bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi)); 303 fi.fin_fi.fi_p = IPPROTO_UDP; 304 fi.fin_data[0] = port; 305 fi.fin_data[1] = 0; 306 fi.fin_dp = (char *)&udp; 307 308 nat2 = nat_new(&fi, nat->nat_ptr, NULL, 309 NAT_SLAVE|IPN_UDP|SI_W_DPORT, 310 NAT_OUTBOUND); 311 if (nat2 != NULL) { 312 (void) nat_proto(&fi, nat2, IPN_UDP); 313 nat_update(&fi, nat2, nat2->nat_ptr); 314 315 nat2->nat_ptr->in_hits++; 316 #ifdef IPFILTER_LOG 317 nat_log(nat2, (u_int)(nat->nat_ptr->in_redir), 318 ifs); 319 #endif 320 bcopy((caddr_t)&ip->ip_src.s_addr, 321 data + off, 4); 322 bcopy((caddr_t)&nat2->nat_outport, 323 data + off + 4, 2); 324 } 325 } 326 } 327 return 0; 328 } 329