]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/ip_msnrpc_pxy.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / ip_msnrpc_pxy.c
1 /*      $FreeBSD$       */
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  */
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
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
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
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
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
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 }