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