1/* $NetBSD: ip_raudio_pxy.c,v 1.2 2012/03/23 20:39:50 christos Exp $ */ 2 3/* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * Id: ip_raudio_pxy.c,v 1.1.1.2 2012/07/22 13:45:33 darrenr Exp 9 */ 10 11#include <sys/cdefs.h> 12__KERNEL_RCSID(1, "$NetBSD: ip_raudio_pxy.c,v 1.2 2012/03/23 20:39:50 christos Exp $"); 13 14#define IPF_RAUDIO_PROXY 15 16 17void ipf_p_raudio_main_load(void); 18void ipf_p_raudio_main_unload(void); 19int ipf_p_raudio_new(void *, fr_info_t *, ap_session_t *, nat_t *); 20int ipf_p_raudio_in(void *, fr_info_t *, ap_session_t *, nat_t *); 21int ipf_p_raudio_out(void *, fr_info_t *, ap_session_t *, nat_t *); 22 23static frentry_t raudiofr; 24 25int raudio_proxy_init = 0; 26 27 28/* 29 * Real Audio application proxy initialization. 30 */ 31void 32ipf_p_raudio_main_load(void) 33{ 34 bzero((char *)&raudiofr, sizeof(raudiofr)); 35 raudiofr.fr_ref = 1; 36 raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 37 MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock"); 38 raudio_proxy_init = 1; 39} 40 41 42void 43ipf_p_raudio_main_unload(void) 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 */ 55int 56ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 57{ 58 raudio_t *rap; 59 60 nat = nat; /* LINT */ 61 62 if (fin->fin_v != 4) 63 return -1; 64 65 KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); 66 if (aps->aps_data == NULL) 67 return -1; 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 78int 79ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_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 183ipf_p_raudio_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 184{ 185 unsigned char membuf[IPF_MAXPORTLEN + 1], *s; 186 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 187 raudio_t *rap = aps->aps_data; 188 ipf_main_softc_t *softc; 189 ipf_nat_softc_t *softn; 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 softc = fin->fin_main_soft; 202 softn = softc->ipf_nat_soft; 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_ndstip; 278 ip->ip_dst = nat->nat_odstip; 279 280 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 281 bzero((char *)tcp2, sizeof(*tcp2)); 282 TCP_OFF_A(tcp2, 5); 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 = htons(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 MUTEX_ENTER(&softn->ipf_nat_new); 302 nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL, 303 NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT), 304 NAT_OUTBOUND); 305 MUTEX_EXIT(&softn->ipf_nat_new); 306 if (nat2 != NULL) { 307 (void) ipf_nat_proto(&fi, nat2, IPN_UDP); 308 MUTEX_ENTER(&nat2->nat_lock); 309 ipf_nat_update(&fi, nat2); 310 MUTEX_EXIT(&nat2->nat_lock); 311 312 (void) ipf_state_add(softc, &fi, NULL, 313 (sp ? 0 : SI_W_SPORT)); 314 } 315 } 316 317 if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { 318 sp = rap->rap_plport; 319 tcp2->th_sport = htons(sp); 320 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 321 fi.fin_data[0] = sp; 322 fi.fin_data[1] = 0; 323 fi.fin_out = 1; 324 MUTEX_ENTER(&softn->ipf_nat_new); 325 nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL, 326 NAT_SLAVE|IPN_UDP|SI_W_DPORT, 327 NAT_OUTBOUND); 328 MUTEX_EXIT(&softn->ipf_nat_new); 329 if (nat2 != NULL) { 330 (void) ipf_nat_proto(&fi, nat2, IPN_UDP); 331 MUTEX_ENTER(&nat2->nat_lock); 332 ipf_nat_update(&fi, nat2); 333 MUTEX_EXIT(&nat2->nat_lock); 334 335 (void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT); 336 } 337 } 338 339 ip->ip_p = swp; 340 ip->ip_len = slen; 341 ip->ip_src = swa; 342 ip->ip_dst = swb; 343 return 0; 344} 345