ip_raudio_pxy.c revision 67853
157126Sguido/* 257126Sguido * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c 67853 2000-10-29 07:53:05Z darrenr $ 357126Sguido */ 453642Sguido#if SOLARIS && defined(_KERNEL) 553642Sguidoextern kmutex_t ipf_rw; 653642Sguido#endif 753642Sguido 853642Sguido#define IPF_RAUDIO_PROXY 953642Sguido 1053642Sguido 1153642Sguidoint ippr_raudio_init __P((void)); 1253642Sguidoint ippr_raudio_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 1353642Sguidoint ippr_raudio_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 1453642Sguidoint ippr_raudio_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 1553642Sguido 1653642Sguidostatic frentry_t raudiofr; 1753642Sguido 1853642Sguido 1953642Sguido/* 2053642Sguido * Real Audio application proxy initialization. 2153642Sguido */ 2253642Sguidoint ippr_raudio_init() 2353642Sguido{ 2453642Sguido bzero((char *)&raudiofr, sizeof(raudiofr)); 2553642Sguido raudiofr.fr_ref = 1; 2653642Sguido raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 2753642Sguido return 0; 2853642Sguido} 2953642Sguido 3053642Sguido 3153642Sguido/* 3253642Sguido * Setup for a new proxy to handle Real Audio. 3353642Sguido */ 3453642Sguidoint ippr_raudio_new(fin, ip, aps, nat) 3553642Sguidofr_info_t *fin; 3653642Sguidoip_t *ip; 3753642Sguidoap_session_t *aps; 3853642Sguidonat_t *nat; 3953642Sguido{ 4053642Sguido raudio_t *rap; 4153642Sguido 4253642Sguido 4353642Sguido KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); 4460857Sdarrenr if (aps->aps_data == NULL) 4560857Sdarrenr return -1; 4660857Sdarrenr 4760857Sdarrenr bzero(aps->aps_data, sizeof(raudio_t)); 4860857Sdarrenr rap = aps->aps_data; 4960857Sdarrenr aps->aps_psiz = sizeof(raudio_t); 5060857Sdarrenr rap->rap_mode = RAP_M_TCP; /* default is for TCP */ 5153642Sguido return 0; 5253642Sguido} 5353642Sguido 5453642Sguido 5553642Sguido 5653642Sguidoint ippr_raudio_out(fin, ip, aps, nat) 5753642Sguidofr_info_t *fin; 5853642Sguidoip_t *ip; 5953642Sguidoap_session_t *aps; 6053642Sguidonat_t *nat; 6153642Sguido{ 6253642Sguido raudio_t *rap = aps->aps_data; 6355929Sguido unsigned char membuf[512 + 1], *s; 6455929Sguido u_short id = 0; 6555929Sguido tcphdr_t *tcp; 6655929Sguido int off, dlen; 6753642Sguido int len = 0; 6853642Sguido mb_t *m; 6953642Sguido#if SOLARIS 7053642Sguido mb_t *m1; 7153642Sguido#endif 7253642Sguido 7353642Sguido /* 7453642Sguido * If we've already processed the start messages, then nothing left 7553642Sguido * for the proxy to do. 7653642Sguido */ 7753642Sguido if (rap->rap_eos == 1) 7853642Sguido return 0; 7953642Sguido 8053642Sguido tcp = (tcphdr_t *)fin->fin_dp; 8153642Sguido off = (ip->ip_hl << 2) + (tcp->th_off << 2); 8253642Sguido bzero(membuf, sizeof(membuf)); 8353642Sguido#if SOLARIS 8453642Sguido m = fin->fin_qfm; 8553642Sguido 8653642Sguido dlen = msgdsize(m) - off; 8753642Sguido if (dlen <= 0) 8853642Sguido return 0; 8955929Sguido copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); 9053642Sguido#else 9153642Sguido m = *(mb_t **)fin->fin_mp; 9253642Sguido 9353642Sguido dlen = mbufchainlen(m) - off; 9453642Sguido if (dlen <= 0) 9553642Sguido return 0; 9655929Sguido m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); 9753642Sguido#endif 9853642Sguido /* 9953642Sguido * In all the startup parsing, ensure that we don't go outside 10053642Sguido * the packet buffer boundary. 10153642Sguido */ 10253642Sguido /* 10353642Sguido * Look for the start of connection "PNA" string if not seen yet. 10453642Sguido */ 10553642Sguido if (rap->rap_seenpna == 0) { 10655929Sguido s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); 10753642Sguido if (s == NULL) 10853642Sguido return 0; 10953642Sguido s += 3; 11053642Sguido rap->rap_seenpna = 1; 11153642Sguido } else 11253642Sguido s = membuf; 11353642Sguido 11453642Sguido /* 11553642Sguido * Directly after the PNA will be the version number of this 11653642Sguido * connection. 11753642Sguido */ 11853642Sguido if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) { 11953642Sguido if ((s + 1) - membuf < dlen) { 12053642Sguido rap->rap_version = (*s << 8) | *(s + 1); 12153642Sguido s += 2; 12253642Sguido rap->rap_seenver = 1; 12353642Sguido } else 12453642Sguido return 0; 12553642Sguido } 12653642Sguido 12753642Sguido /* 12853642Sguido * Now that we've been past the PNA and version number, we're into the 12953642Sguido * startup messages block. This ends when a message with an ID of 0. 13053642Sguido */ 13153642Sguido while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) { 13253642Sguido if (rap->rap_gotid == 0) { 13353642Sguido id = (*s << 8) | *(s + 1); 13453642Sguido s += 2; 13553642Sguido rap->rap_gotid = 1; 13653642Sguido if (id == RA_ID_END) { 13753642Sguido rap->rap_eos = 1; 13853642Sguido break; 13953642Sguido } 14053642Sguido } else if (rap->rap_gotlen == 0) { 14153642Sguido len = (*s << 8) | *(s + 1); 14253642Sguido s += 2; 14353642Sguido rap->rap_gotlen = 1; 14453642Sguido } 14553642Sguido 14653642Sguido if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) { 14753642Sguido if (id == RA_ID_UDP) { 14853642Sguido rap->rap_mode &= ~RAP_M_TCP; 14953642Sguido rap->rap_mode |= RAP_M_UDP; 15053642Sguido rap->rap_plport = (*s << 8) | *(s + 1); 15153642Sguido } else if (id == RA_ID_ROBUST) { 15253642Sguido rap->rap_mode |= RAP_M_ROBUST; 15353642Sguido rap->rap_prport = (*s << 8) | *(s + 1); 15453642Sguido } 15553642Sguido s += len; 15653642Sguido rap->rap_gotlen = 0; 15753642Sguido rap->rap_gotid = 0; 15853642Sguido } 15953642Sguido } 16055929Sguido return 0; 16153642Sguido} 16253642Sguido 16353642Sguido 16453642Sguidoint ippr_raudio_in(fin, ip, aps, nat) 16553642Sguidofr_info_t *fin; 16653642Sguidoip_t *ip; 16753642Sguidoap_session_t *aps; 16853642Sguidonat_t *nat; 16953642Sguido{ 17055929Sguido unsigned char membuf[IPF_MAXPORTLEN + 1], *s; 17155929Sguido tcphdr_t *tcp, tcph, *tcp2 = &tcph; 17253642Sguido raudio_t *rap = aps->aps_data; 17355929Sguido struct in_addr swa, swb; 17460857Sdarrenr int off, dlen, slen; 17567614Sdarrenr int a1, a2, a3, a4; 17655929Sguido u_short sp, dp; 17755929Sguido fr_info_t fi; 17853642Sguido tcp_seq seq; 17955929Sguido nat_t *ipn; 18055929Sguido u_char swp; 18153642Sguido mb_t *m; 18253642Sguido#if SOLARIS 18353642Sguido mb_t *m1; 18453642Sguido#endif 18553642Sguido 18655929Sguido /* 18755929Sguido * Wait until we've seen the end of the start messages and even then 18855929Sguido * only proceed further if we're using UDP. If they want to use TCP 18955929Sguido * then data is sent back on the same channel that is already open. 19055929Sguido */ 19155929Sguido if (rap->rap_sdone != 0) 19253642Sguido return 0; 19353642Sguido 19453642Sguido tcp = (tcphdr_t *)fin->fin_dp; 19553642Sguido off = (ip->ip_hl << 2) + (tcp->th_off << 2); 19653642Sguido m = *(mb_t **)fin->fin_mp; 19753642Sguido 19853642Sguido#if SOLARIS 19953642Sguido m = fin->fin_qfm; 20053642Sguido 20153642Sguido dlen = msgdsize(m) - off; 20253642Sguido if (dlen <= 0) 20353642Sguido return 0; 20453642Sguido bzero(membuf, sizeof(membuf)); 20555929Sguido copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); 20653642Sguido#else 20753642Sguido dlen = mbufchainlen(m) - off; 20853642Sguido if (dlen <= 0) 20953642Sguido return 0; 21053642Sguido bzero(membuf, sizeof(membuf)); 21155929Sguido m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); 21253642Sguido#endif 21353642Sguido 21453642Sguido seq = ntohl(tcp->th_seq); 21553642Sguido /* 21653642Sguido * Check to see if the data in this packet is of interest to us. 21753642Sguido * We only care for the first 19 bytes coming back from the server. 21853642Sguido */ 21953642Sguido if (rap->rap_sseq == 0) { 22055929Sguido s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); 22153642Sguido if (s == NULL) 22253642Sguido return 0; 22353642Sguido a1 = s - membuf; 22453642Sguido dlen -= a1; 22553642Sguido a1 = 0; 22653642Sguido rap->rap_sseq = seq; 22753642Sguido a2 = MIN(dlen, sizeof(rap->rap_svr)); 22853642Sguido } else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) { 22953642Sguido /* 23053642Sguido * seq # which is the start of data and from that the offset 23153642Sguido * into the buffer array. 23253642Sguido */ 23353642Sguido a1 = seq - rap->rap_sseq; 23453642Sguido a2 = MIN(dlen, sizeof(rap->rap_svr)); 23553642Sguido a2 -= a1; 23653642Sguido s = membuf; 23753642Sguido } else 23853642Sguido return 0; 23953642Sguido 24055929Sguido for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) { 24153642Sguido rap->rap_sbf |= (1 << a3); 24253642Sguido rap->rap_svr[a3] = *s++; 24353642Sguido } 24455929Sguido 24555929Sguido if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos)) /* 19 bits */ 24655929Sguido return 0; 24755929Sguido rap->rap_sdone = 1; 24855929Sguido 24955929Sguido s = (u_char *)rap->rap_svr + 11; 25055929Sguido if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) { 25155929Sguido s += 2; 25253642Sguido rap->rap_srport = (*s << 8) | *(s + 1); 25353642Sguido } 25455929Sguido 25555929Sguido swp = ip->ip_p; 25655929Sguido swa = ip->ip_src; 25755929Sguido swb = ip->ip_dst; 25855929Sguido 25955929Sguido ip->ip_p = IPPROTO_UDP; 26055929Sguido ip->ip_src = nat->nat_inip; 26155929Sguido ip->ip_dst = nat->nat_oip; 26255929Sguido 26355929Sguido bcopy((char *)fin, (char *)&fi, sizeof(fi)); 26455929Sguido bzero((char *)tcp2, sizeof(*tcp2)); 26560857Sdarrenr tcp2->th_off = 5; 26655929Sguido fi.fin_dp = (char *)tcp2; 26755929Sguido fi.fin_fr = &raudiofr; 26867853Sdarrenr fi.fin_dlen = sizeof(*tcp2); 26955929Sguido tcp2->th_win = htons(8192); 27060857Sdarrenr slen = ip->ip_len; 27160857Sdarrenr ip->ip_len = fin->fin_hlen + sizeof(*tcp); 27255929Sguido 27355929Sguido if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && 27455929Sguido (rap->rap_srport != 0)) { 27555929Sguido dp = rap->rap_srport; 27655929Sguido sp = rap->rap_prport; 27755929Sguido tcp2->th_sport = htons(sp); 27855929Sguido tcp2->th_dport = htons(dp); 27955929Sguido fi.fin_data[0] = dp; 28055929Sguido fi.fin_data[1] = sp; 28155929Sguido ipn = nat_new(nat->nat_ptr, ip, &fi, 28260857Sdarrenr IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); 28355929Sguido if (ipn != NULL) { 28455929Sguido ipn->nat_age = fr_defnatage; 28555929Sguido (void) fr_addstate(ip, &fi, sp ? 0 : FI_W_SPORT); 28655929Sguido } 28755929Sguido } 28855929Sguido 28955929Sguido if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { 29055929Sguido sp = rap->rap_plport; 29155929Sguido tcp2->th_sport = htons(sp); 29255929Sguido tcp2->th_dport = 0; /* XXX - don't specify remote port */ 29355929Sguido fi.fin_data[0] = sp; 29455929Sguido fi.fin_data[1] = 0; 29555929Sguido ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_UDP|FI_W_DPORT, 29655929Sguido NAT_OUTBOUND); 29755929Sguido if (ipn != NULL) { 29855929Sguido ipn->nat_age = fr_defnatage; 29955929Sguido (void) fr_addstate(ip, &fi, FI_W_DPORT); 30055929Sguido } 30155929Sguido } 30260857Sdarrenr 30355929Sguido ip->ip_p = swp; 30460857Sdarrenr ip->ip_len = slen; 30555929Sguido ip->ip_src = swa; 30655929Sguido ip->ip_dst = swb; 30753642Sguido return 0; 30853642Sguido} 309