1 /* 2 * Copyright (C) 1998-2003 by Darren Reed 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * $Id: ip_raudio_pxy.c,v 1.40.2.3 2005/02/04 10:22:55 darrenr Exp $ 7 * 8 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 */ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 #define IPF_RAUDIO_PROXY 15 16 typedef struct ifs_raudiopxy { 17 frentry_t raudiofr; 18 int raudio_proxy_init; 19 } ifs_raudiopxy_t; 20 21 int ippr_raudio_init __P((void **, ipf_stack_t *)); 22 void ippr_raudio_fini __P((void **, ipf_stack_t *)); 23 int ippr_raudio_new __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 24 int ippr_raudio_in __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 25 int ippr_raudio_out __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 26 27 /* 28 * Real Audio application proxy initialization. 29 */ 30 /*ARGSUSED*/ 31 int ippr_raudio_init(private, ifs) 32 void **private; 33 ipf_stack_t *ifs; 34 { 35 ifs_raudiopxy_t *ifsraudio; 36 37 KMALLOC(ifsraudio, ifs_raudiopxy_t *); 38 if (ifsraudio == NULL) 39 return -1; 40 41 bzero((char *)&ifsraudio->raudiofr, sizeof(ifsraudio->raudiofr)); 42 ifsraudio->raudiofr.fr_ref = 1; 43 ifsraudio->raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 44 MUTEX_INIT(&ifsraudio->raudiofr.fr_lock, "Real Audio proxy rule lock"); 45 ifsraudio->raudio_proxy_init = 1; 46 47 *private = (void *)ifsraudio; 48 49 return 0; 50 } 51 52 53 /*ARGSUSED*/ 54 void ippr_raudio_fini(private, ifs) 55 void **private; 56 ipf_stack_t *ifs; 57 { 58 ifs_raudiopxy_t *ifsraudio = *((ifs_raudiopxy_t **)private); 59 60 if (ifsraudio->raudio_proxy_init == 1) { 61 MUTEX_DESTROY(&ifsraudio->raudiofr.fr_lock); 62 ifsraudio->raudio_proxy_init = 0; 63 } 64 65 KFREE(ifsraudio); 66 *private = NULL; 67 } 68 69 70 /* 71 * Setup for a new proxy to handle Real Audio. 72 */ 73 /*ARGSUSED*/ 74 int ippr_raudio_new(fin, aps, nat, private) 75 fr_info_t *fin; 76 ap_session_t *aps; 77 nat_t *nat; 78 void *private; 79 { 80 raudio_t *rap; 81 82 KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); 83 if (aps->aps_data == NULL) 84 return -1; 85 86 fin = fin; /* LINT */ 87 nat = nat; /* LINT */ 88 89 bzero(aps->aps_data, sizeof(raudio_t)); 90 rap = aps->aps_data; 91 aps->aps_psiz = sizeof(raudio_t); 92 rap->rap_mode = RAP_M_TCP; /* default is for TCP */ 93 return 0; 94 } 95 96 97 /*ARGSUSED*/ 98 int ippr_raudio_out(fin, aps, nat, private) 99 fr_info_t *fin; 100 ap_session_t *aps; 101 nat_t *nat; 102 void *private; 103 { 104 raudio_t *rap = aps->aps_data; 105 unsigned char membuf[512 + 1], *s; 106 u_short id = 0; 107 tcphdr_t *tcp; 108 int off, dlen; 109 int len = 0; 110 mb_t *m; 111 112 nat = nat; /* LINT */ 113 114 /* 115 * If we've already processed the start messages, then nothing left 116 * for the proxy to do. 117 */ 118 if (rap->rap_eos == 1) 119 return 0; 120 121 m = fin->fin_m; 122 tcp = (tcphdr_t *)fin->fin_dp; 123 off = (char *)tcp - (char *)fin->fin_ip; 124 off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 125 126 #ifdef __sgi 127 dlen = fin->fin_plen - off; 128 #else 129 dlen = MSGDSIZE(m) - off; 130 #endif 131 if (dlen <= 0) 132 return 0; 133 134 if (dlen > sizeof(membuf)) 135 dlen = sizeof(membuf); 136 137 bzero((char *)membuf, sizeof(membuf)); 138 COPYDATA(m, off, dlen, (char *)membuf); 139 /* 140 * In all the startup parsing, ensure that we don't go outside 141 * the packet buffer boundary. 142 */ 143 /* 144 * Look for the start of connection "PNA" string if not seen yet. 145 */ 146 if (rap->rap_seenpna == 0) { 147 s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); 148 if (s == NULL) 149 return 0; 150 s += 3; 151 rap->rap_seenpna = 1; 152 } else 153 s = membuf; 154 155 /* 156 * Directly after the PNA will be the version number of this 157 * connection. 158 */ 159 if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) { 160 if ((s + 1) - membuf < dlen) { 161 rap->rap_version = (*s << 8) | *(s + 1); 162 s += 2; 163 rap->rap_seenver = 1; 164 } else 165 return 0; 166 } 167 168 /* 169 * Now that we've been past the PNA and version number, we're into the 170 * startup messages block. This ends when a message with an ID of 0. 171 */ 172 while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) { 173 if (rap->rap_gotid == 0) { 174 id = (*s << 8) | *(s + 1); 175 s += 2; 176 rap->rap_gotid = 1; 177 if (id == RA_ID_END) { 178 rap->rap_eos = 1; 179 break; 180 } 181 } else if (rap->rap_gotlen == 0) { 182 len = (*s << 8) | *(s + 1); 183 s += 2; 184 rap->rap_gotlen = 1; 185 } 186 187 if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) { 188 if (id == RA_ID_UDP) { 189 rap->rap_mode &= ~RAP_M_TCP; 190 rap->rap_mode |= RAP_M_UDP; 191 rap->rap_plport = (*s << 8) | *(s + 1); 192 } else if (id == RA_ID_ROBUST) { 193 rap->rap_mode |= RAP_M_ROBUST; 194 rap->rap_prport = (*s << 8) | *(s + 1); 195 } 196 s += len; 197 rap->rap_gotlen = 0; 198 rap->rap_gotid = 0; 199 } 200 } 201 return 0; 202 } 203 204 205 int ippr_raudio_in(fin, aps, nat, private) 206 fr_info_t *fin; 207 ap_session_t *aps; 208 nat_t *nat; 209 void *private; 210 { 211 unsigned char membuf[IPF_MAXPORTLEN + 1], *s; 212 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 213 raudio_t *rap = aps->aps_data; 214 struct in_addr swa, swb; 215 int off, dlen, slen; 216 int a1, a2, a3, a4; 217 u_short sp, dp; 218 fr_info_t fi; 219 tcp_seq seq; 220 nat_t *nat2; 221 u_char swp; 222 ip_t *ip; 223 mb_t *m; 224 ipf_stack_t *ifs = fin->fin_ifs; 225 ifs_raudiopxy_t *ifsraudio = (ifs_raudiopxy_t *)private; 226 227 /* 228 * Wait until we've seen the end of the start messages and even then 229 * only proceed further if we're using UDP. If they want to use TCP 230 * then data is sent back on the same channel that is already open. 231 */ 232 if (rap->rap_sdone != 0) 233 return 0; 234 235 m = fin->fin_m; 236 tcp = (tcphdr_t *)fin->fin_dp; 237 off = (char *)tcp - (char *)fin->fin_ip; 238 off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 239 240 #ifdef __sgi 241 dlen = fin->fin_plen - off; 242 #else 243 dlen = MSGDSIZE(m) - off; 244 #endif 245 if (dlen <= 0) 246 return 0; 247 248 if (dlen > sizeof(membuf)) 249 dlen = sizeof(membuf); 250 251 bzero((char *)membuf, sizeof(membuf)); 252 COPYDATA(m, off, dlen, (char *)membuf); 253 254 seq = ntohl(tcp->th_seq); 255 /* 256 * Check to see if the data in this packet is of interest to us. 257 * We only care for the first 19 bytes coming back from the server. 258 */ 259 if (rap->rap_sseq == 0) { 260 s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); 261 if (s == NULL) 262 return 0; 263 a1 = s - membuf; 264 dlen -= a1; 265 a1 = 0; 266 rap->rap_sseq = seq; 267 a2 = MIN(dlen, sizeof(rap->rap_svr)); 268 } else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) { 269 /* 270 * seq # which is the start of data and from that the offset 271 * into the buffer array. 272 */ 273 a1 = seq - rap->rap_sseq; 274 a2 = MIN(dlen, sizeof(rap->rap_svr)); 275 a2 -= a1; 276 s = membuf; 277 } else 278 return 0; 279 280 for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) { 281 rap->rap_sbf |= (1 << a3); 282 rap->rap_svr[a3] = *s++; 283 } 284 285 if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos)) /* 19 bits */ 286 return 0; 287 rap->rap_sdone = 1; 288 289 s = (u_char *)rap->rap_svr + 11; 290 if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) { 291 s += 2; 292 rap->rap_srport = (*s << 8) | *(s + 1); 293 } 294 295 ip = fin->fin_ip; 296 swp = ip->ip_p; 297 swa = ip->ip_src; 298 swb = ip->ip_dst; 299 300 ip->ip_p = IPPROTO_UDP; 301 ip->ip_src = nat->nat_inip; 302 ip->ip_dst = nat->nat_oip; 303 304 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 305 bzero((char *)tcp2, sizeof(*tcp2)); 306 TCP_OFF_A(tcp2, 5); 307 fi.fin_state = NULL; 308 fi.fin_nat = NULL; 309 fi.fin_flx |= FI_IGNORE; 310 fi.fin_dp = (char *)tcp2; 311 fi.fin_fr = &ifsraudio->raudiofr; 312 fi.fin_dlen = sizeof(*tcp2); 313 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 314 tcp2->th_win = htons(8192); 315 slen = ip->ip_len; 316 ip->ip_len = fin->fin_hlen + sizeof(*tcp); 317 318 if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && 319 (rap->rap_srport != 0)) { 320 dp = rap->rap_srport; 321 sp = rap->rap_prport; 322 tcp2->th_sport = htons(sp); 323 tcp2->th_dport = htons(dp); 324 fi.fin_data[0] = dp; 325 fi.fin_data[1] = sp; 326 fi.fin_out = 0; 327 nat2 = nat_new(&fi, nat->nat_ptr, NULL, 328 NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT), 329 NAT_OUTBOUND); 330 if (nat2 != NULL) { 331 (void) nat_proto(&fi, nat2, IPN_UDP); 332 nat_update(&fi, nat2, nat2->nat_ptr); 333 334 (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT)); 335 if (fi.fin_state != NULL) 336 fr_statederef(&fi, (ipstate_t **)&fi.fin_state, ifs); 337 } 338 } 339 340 if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { 341 sp = rap->rap_plport; 342 tcp2->th_sport = htons(sp); 343 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 344 fi.fin_data[0] = sp; 345 fi.fin_data[1] = 0; 346 fi.fin_out = 1; 347 nat2 = nat_new(&fi, nat->nat_ptr, NULL, 348 NAT_SLAVE|IPN_UDP|SI_W_DPORT, 349 NAT_OUTBOUND); 350 if (nat2 != NULL) { 351 (void) nat_proto(&fi, nat2, IPN_UDP); 352 nat_update(&fi, nat2, nat2->nat_ptr); 353 354 (void) fr_addstate(&fi, NULL, SI_W_DPORT); 355 if (fi.fin_state != NULL) 356 fr_statederef(&fi, (ipstate_t **)&fi.fin_state, ifs); 357 } 358 } 359 360 ip->ip_p = swp; 361 ip->ip_len = slen; 362 ip->ip_src = swa; 363 ip->ip_dst = swb; 364 return 0; 365 } 366