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