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