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