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