ip_msnrpc_pxy.c revision 369245
1/*	$FreeBSD: stable/11/contrib/ipfilter/ip_msnrpc_pxy.c 369245 2021-02-09 13:47:46Z git2svn $	*/
2
3/*
4 * Copyright (C) 2000-2003 by Darren Reed
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * Simple DCE transparent proxy for MSN RPC.
9 *
10 * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ********
11 *
12 * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp
13 */
14
15#define	IPF_MSNRPC_PROXY
16
17#define	IPF_MINMSNRPCLEN	24
18#define	IPF_MSNRPCSKIP		(2 + 19 + 2 + 2 + 2 + 19 + 2 + 2)
19
20
21typedef	struct	msnrpchdr	{
22	u_char	mrh_major;	/* major # == 5 */
23	u_char	mrh_minor;	/* minor # == 0 */
24	u_char	mrh_type;
25	u_char	mrh_flags;
26	u_32_t	mrh_endian;
27	u_short	mrh_dlen;	/* data size */
28	u_short	mrh_alen;	/* authentication length */
29	u_32_t	mrh_cid;	/* call identifier */
30	u_32_t	mrh_hint;	/* allocation hint */
31	u_short	mrh_ctxt;	/* presentation context hint */
32	u_char	mrh_ccnt;	/* cancel count */
33	u_char	mrh_ans;
34} msnrpchdr_t;
35
36int ippr_msnrpc_init(void);
37void ippr_msnrpc_fini(void);
38int ippr_msnrpc_new(fr_info_t *, ap_session_t *, nat_t *);
39int ippr_msnrpc_out(fr_info_t *, ap_session_t *, nat_t *);
40int ippr_msnrpc_in(fr_info_t *, ap_session_t *, nat_t *);
41int ippr_msnrpc_check(ip_t *, msnrpchdr_t *);
42
43static	frentry_t	msnfr;
44
45int	msn_proxy_init = 0;
46
47/*
48 * Initialize local structures.
49 */
50int ippr_msnrpc_init()
51{
52	bzero((char *)&msnfr, sizeof(msnfr));
53	msnfr.fr_ref = 1;
54	msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
55	MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock");
56	msn_proxy_init = 1;
57
58	return 0;
59}
60
61
62void ippr_msnrpc_fini()
63{
64	if (msn_proxy_init == 1) {
65		MUTEX_DESTROY(&msnfr.fr_lock);
66		msn_proxy_init = 0;
67	}
68}
69
70
71int ippr_msnrpc_new(fin, aps, nat)
72fr_info_t *fin;
73ap_session_t *aps;
74nat_t *nat;
75{
76	msnrpcinfo_t *mri;
77
78	KMALLOC(mri, msnrpcinfo_t *);
79	if (mri == NULL)
80		return -1;
81	aps->aps_data = mri;
82	aps->aps_psiz = sizeof(msnrpcinfo_t);
83
84	bzero((char *)mri, sizeof(*mri));
85	mri->mri_cmd[0] = 0xff;
86	mri->mri_cmd[1] = 0xff;
87	return 0;
88}
89
90
91int ippr_msnrpc_check(ip, mrh)
92ip_t *ip;
93msnrpchdr_t *mrh;
94{
95	if (mrh->mrh_major != 5)
96		return -1;
97	if (mrh->mrh_minor != 0)
98		return -1;
99	if (mrh->mrh_alen != 0)
100		return -1;
101	if (mrh->mrh_endian == 0x10) {
102		/* Both gateway and packet match endian */
103		if (mrh->mrh_dlen > ip->ip_len)
104			return -1;
105		if (mrh->mrh_type == 0 || mrh->mrh_type == 2)
106			if (mrh->mrh_hint > ip->ip_len)
107				return -1;
108	} else if (mrh->mrh_endian == 0x10000000) {
109		/* XXX - Endian mismatch - should be swapping! */
110		return -1;
111	} else {
112		return -1;
113	}
114	return 0;
115}
116
117
118int ippr_msnrpc_out(fin, ip, aps, nat)
119fr_info_t *fin;
120ip_t *ip;
121ap_session_t *aps;
122nat_t *nat;
123{
124	msnrpcinfo_t *mri;
125	msnrpchdr_t *mrh;
126	tcphdr_t *tcp;
127	int dlen;
128
129	mri = aps->aps_data;
130	if (mri == NULL)
131		return 0;
132
133	tcp = (tcphdr_t *)fin->fin_dp;
134	dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
135	if (dlen < IPF_MINMSNRPCLEN)
136		return 0;
137
138	mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2));
139	if (ippr_msnrpc_check(ip, mrh))
140		return 0;
141
142	mri->mri_valid++;
143
144	switch (mrh->mrh_type)
145	{
146	case 0x0b :	/* BIND */
147	case 0x00 :	/* REQUEST */
148		break;
149	case 0x0c :	/* BIND ACK */
150	case 0x02 :	/* RESPONSE */
151	default:
152		return 0;
153	}
154	mri->mri_cmd[1] = mrh->mrh_type;
155	return 0;
156}
157
158
159int ippr_msnrpc_in(fin, ip, aps, nat)
160fr_info_t *fin;
161ip_t *ip;
162ap_session_t *aps;
163nat_t *nat;
164{
165	tcphdr_t *tcp, tcph, *tcp2 = &tcph;
166	int dlen, sz, sz2, i;
167	msnrpcinfo_t *mri;
168	msnrpchdr_t *mrh;
169	fr_info_t fi;
170	u_short len;
171	char *s;
172
173	mri = aps->aps_data;
174	if (mri == NULL)
175		return 0;
176	tcp = (tcphdr_t *)fin->fin_dp;
177	dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
178	if (dlen < IPF_MINMSNRPCLEN)
179		return 0;
180
181	mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2));
182	if (ippr_msnrpc_check(ip, mrh))
183		return 0;
184
185	mri->mri_valid++;
186
187	switch (mrh->mrh_type)
188	{
189	case 0x0c :	/* BIND ACK */
190		if (mri->mri_cmd[1] != 0x0b)
191			return 0;
192		break;
193	case 0x02 :	/* RESPONSE */
194		if (mri->mri_cmd[1] != 0x00)
195			return 0;
196		break;
197	case 0x0b :	/* BIND */
198	case 0x00 :	/* REQUEST */
199	default:
200		return 0;
201	}
202	mri->mri_cmd[0] = mrh->mrh_type;
203	dlen -= sizeof(*mrh);
204
205	/*
206	 * Only processes RESPONSE's
207	 */
208	if (mrh->mrh_type != 0x02)
209		return 0;
210
211	/*
212	 * Skip over some bytes...what are these really ?
213	 */
214	if (dlen <= 44)
215		return 0;
216	s = (char *)(mrh + 1) + 20;
217	dlen -= 20;
218	bcopy(s, (char *)&len, sizeof(len));
219	if (len == 1) {
220		s += 20;
221		dlen -= 20;
222	} else if (len == 2) {
223		s += 24;
224		dlen -= 24;
225	} else
226		return 0;
227
228	if (dlen <= 10)
229		return 0;
230	dlen -= 10;
231	bcopy(s, (char *)&sz, sizeof(sz));
232	s += sizeof(sz);
233	bcopy(s, (char *)&sz2, sizeof(sz2));
234	s += sizeof(sz2);
235	if (sz2 != sz)
236		return 0;
237	if (sz > dlen)
238		return 0;
239	if (*s++ != 5)
240		return 0;
241	if (*s++ != 0)
242		return 0;
243	sz -= IPF_MSNRPCSKIP;
244	s += IPF_MSNRPCSKIP;
245	dlen -= IPF_MSNRPCSKIP;
246
247	do {
248		if (sz < 7 || dlen < 7)
249			break;
250		bcopy(s, (char *)&len, sizeof(len));
251		if (dlen < len)
252			break;
253		if (sz < len)
254			break;
255
256		if (len != 1)
257			break;
258		sz -= 3;
259		i = *(s + 2);
260		s += 3;
261		dlen -= 3;
262
263		bcopy(s, (char *)&len, sizeof(len));
264		if (dlen < len)
265			break;
266		if (sz < len)
267			break;
268		s += sizeof(len);
269
270		switch (i)
271		{
272		case 7 :
273			if (len == 2) {
274				bcopy(s, (char *)&mri->mri_rport, 2);
275				mri->mri_flags |= 1;
276			}
277			break;
278		case 9 :
279			if (len == 4) {
280				bcopy(s, (char *)&mri->mri_raddr, 4);
281				mri->mri_flags |= 2;
282			}
283			break;
284		default :
285			break;
286		}
287		sz -= len;
288		s += len;
289		dlen -= len;
290	} while (sz > 0);
291
292	if (mri->mri_flags == 3) {
293		int slen;
294
295		bcopy((char *)fin, (char *)&fi, sizeof(fi));
296		bzero((char *)tcp2, sizeof(*tcp2));
297
298		slen = ip->ip_len;
299		ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
300		bcopy((char *)fin, (char *)&fi, sizeof(fi));
301		bzero((char *)tcp2, sizeof(*tcp2));
302		tcp2->th_win = htons(8192);
303		TCP_OFF_A(tcp2, 5);
304		fi.fin_data[0] = htons(mri->mri_rport);
305		tcp2->th_sport = mri->mri_rport;
306		fi.fin_data[1] = 0;
307		tcp2->th_dport = 0;
308		fi.fin_state = NULL;
309		fi.fin_nat = NULL;
310		fi.fin_dlen = sizeof(*tcp2);
311		fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
312		fi.fin_dp = (char *)tcp2;
313		fi.fin_fi.fi_daddr = ip->ip_dst.s_addr;
314		fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr;
315		if (!fi.fin_fr)
316			fi.fin_fr = &msnfr;
317		if (fr_stlookup(&fi, NULL, NULL)) {
318			RWLOCK_EXIT(&ipf_state);
319		} else {
320			(void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE);
321			if (fi.fin_state != NULL)
322				fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
323		}
324		ip->ip_len = slen;
325	}
326	mri->mri_flags = 0;
327	return 0;
328}
329