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