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