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