1 /* $FreeBSD: stable/9/contrib/ipfilter/ip_msnrpc_pxy.c 145519 2005-04-25 18:20:15Z darrenr $ */
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
21 typedef 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
36 int ippr_msnrpc_init __P((void));
37 void ippr_msnrpc_fini __P((void));
38 int ippr_msnrpc_new __P((fr_info_t *, ap_session_t *, nat_t *));
39 int ippr_msnrpc_out __P((fr_info_t *, ap_session_t *, nat_t *));
40 int ippr_msnrpc_in __P((fr_info_t *, ap_session_t *, nat_t *));
41 int ippr_msnrpc_check __P((ip_t *, msnrpchdr_t *));
42
43 static frentry_t msnfr;
44
45 int msn_proxy_init = 0;
46
47 /*
48 * Initialize local structures.
49 */
ippr_msnrpc_init()50 int 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
ippr_msnrpc_fini()62 void 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
ippr_msnrpc_new(fin,aps,nat)71 int ippr_msnrpc_new(fin, aps, nat)
72 fr_info_t *fin;
73 ap_session_t *aps;
74 nat_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
ippr_msnrpc_check(ip,mrh)91 int ippr_msnrpc_check(ip, mrh)
92 ip_t *ip;
93 msnrpchdr_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
ippr_msnrpc_out(fin,ip,aps,nat)118 int ippr_msnrpc_out(fin, ip, aps, nat)
119 fr_info_t *fin;
120 ip_t *ip;
121 ap_session_t *aps;
122 nat_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
ippr_msnrpc_in(fin,ip,aps,nat)159 int ippr_msnrpc_in(fin, ip, aps, nat)
160 fr_info_t *fin;
161 ip_t *ip;
162 ap_session_t *aps;
163 nat_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