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