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