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