1 /* $NetBSD: ip_pptp_pxy.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * Simple PPTP transparent proxy for in-kernel use. For use with the NAT
7 * code.
8 *
9 * Id: ip_pptp_pxy.c,v 1.1.1.2 2012/07/22 13:44:23 darrenr Exp $
10 *
11 */
12 #define IPF_PPTP_PROXY
13
14
15
16 /*
17 * PPTP proxy
18 */
19 typedef struct pptp_side {
20 u_32_t pptps_nexthdr;
21 u_32_t pptps_next;
22 int pptps_state;
23 int pptps_gothdr;
24 int pptps_len;
25 int pptps_bytes;
26 char *pptps_wptr;
27 char pptps_buffer[512];
28 } pptp_side_t;
29
30 typedef struct pptp_pxy {
31 nat_t *pptp_nat;
32 struct ipstate *pptp_state;
33 u_short pptp_call[2];
34 pptp_side_t pptp_side[2];
35 ipnat_t *pptp_rule;
36 } pptp_pxy_t;
37
38 typedef struct pptp_hdr {
39 u_short pptph_len;
40 u_short pptph_type;
41 u_32_t pptph_cookie;
42 } pptp_hdr_t;
43
44 #define PPTP_MSGTYPE_CTL 1
45 #define PPTP_MTCTL_STARTREQ 1
46 #define PPTP_MTCTL_STARTREP 2
47 #define PPTP_MTCTL_STOPREQ 3
48 #define PPTP_MTCTL_STOPREP 4
49 #define PPTP_MTCTL_ECHOREQ 5
50 #define PPTP_MTCTL_ECHOREP 6
51 #define PPTP_MTCTL_OUTREQ 7
52 #define PPTP_MTCTL_OUTREP 8
53 #define PPTP_MTCTL_INREQ 9
54 #define PPTP_MTCTL_INREP 10
55 #define PPTP_MTCTL_INCONNECT 11
56 #define PPTP_MTCTL_CLEAR 12
57 #define PPTP_MTCTL_DISCONNECT 13
58 #define PPTP_MTCTL_WANERROR 14
59 #define PPTP_MTCTL_LINKINFO 15
60
61
62 void ipf_p_pptp_main_load __P((void));
63 void ipf_p_pptp_main_unload __P((void));
64 int ipf_p_pptp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
65 void ipf_p_pptp_del __P((ipf_main_softc_t *, ap_session_t *));
66 int ipf_p_pptp_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
67 void ipf_p_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
68 int ipf_p_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
69 int ipf_p_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
70 int ipf_p_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
71
72 static frentry_t pptpfr;
73
74 static int pptp_proxy_init = 0;
75 static int ipf_p_pptp_debug = 0;
76 static int ipf_p_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */
77
78
79 /*
80 * PPTP application proxy initialization.
81 */
82 void
ipf_p_pptp_main_load()83 ipf_p_pptp_main_load()
84 {
85 bzero((char *)&pptpfr, sizeof(pptpfr));
86 pptpfr.fr_ref = 1;
87 pptpfr.fr_age[0] = ipf_p_pptp_gretimeout;
88 pptpfr.fr_age[1] = ipf_p_pptp_gretimeout;
89 pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
90 MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock");
91 pptp_proxy_init = 1;
92 }
93
94
95 void
ipf_p_pptp_main_unload()96 ipf_p_pptp_main_unload()
97 {
98 if (pptp_proxy_init == 1) {
99 MUTEX_DESTROY(&pptpfr.fr_lock);
100 pptp_proxy_init = 0;
101 }
102 }
103
104
105 /*
106 * Setup for a new PPTP proxy.
107 *
108 * NOTE: The printf's are broken up with %s in them to prevent them being
109 * optimised into puts statements on FreeBSD (this doesn't exist in the kernel)
110 */
111 int
ipf_p_pptp_new(arg,fin,aps,nat)112 ipf_p_pptp_new(arg, fin, aps, nat)
113 void *arg;
114 fr_info_t *fin;
115 ap_session_t *aps;
116 nat_t *nat;
117 {
118 pptp_pxy_t *pptp;
119 ipnat_t *ipn;
120 ipnat_t *np;
121 int size;
122 ip_t *ip;
123
124 if (fin->fin_v != 4)
125 return -1;
126
127 ip = fin->fin_ip;
128 np = nat->nat_ptr;
129 size = np->in_size;
130
131 if (ipf_nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_osrcip,
132 ip->ip_dst) != NULL) {
133 if (ipf_p_pptp_debug > 0)
134 printf("ipf_p_pptp_new: GRE session already exists\n");
135 return -1;
136 }
137
138 KMALLOC(pptp, pptp_pxy_t *);
139 if (pptp == NULL) {
140 if (ipf_p_pptp_debug > 0)
141 printf("ipf_p_pptp_new: malloc for aps_data failed\n");
142 return -1;
143 }
144 KMALLOCS(ipn, ipnat_t *, size);
145 if (ipn == NULL) {
146 KFREE(pptp);
147 return -1;
148 }
149
150 aps->aps_data = pptp;
151 aps->aps_psiz = sizeof(*pptp);
152 bzero((char *)pptp, sizeof(*pptp));
153 bzero((char *)ipn, size);
154 pptp->pptp_rule = ipn;
155
156 /*
157 * Create NAT rule against which the tunnel/transport mapping is
158 * created. This is required because the current NAT rule does not
159 * describe GRE but TCP instead.
160 */
161 ipn->in_size = size;
162 ipn->in_ifps[0] = fin->fin_ifp;
163 ipn->in_apr = NULL;
164 ipn->in_use = 1;
165 ipn->in_hits = 1;
166 ipn->in_ippip = 1;
167 ipn->in_snip = ntohl(nat->nat_nsrcaddr);
168 ipn->in_nsrcaddr = fin->fin_saddr;
169 ipn->in_dnip = ntohl(nat->nat_ndstaddr);
170 ipn->in_ndstaddr = nat->nat_ndstaddr;
171 ipn->in_redir = np->in_redir;
172 ipn->in_osrcaddr = nat->nat_osrcaddr;
173 ipn->in_odstaddr = nat->nat_odstaddr;
174 ipn->in_osrcmsk = 0xffffffff;
175 ipn->in_nsrcmsk = 0xffffffff;
176 ipn->in_odstmsk = 0xffffffff;
177 ipn->in_ndstmsk = 0xffffffff;
178 ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
179 MUTEX_INIT(&ipn->in_lock, "pptp proxy NAT rule");
180
181 ipn->in_namelen = np->in_namelen;
182 bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
183 ipn->in_ifnames[0] = np->in_ifnames[0];
184 ipn->in_ifnames[1] = np->in_ifnames[1];
185
186 ipn->in_pr[0] = IPPROTO_GRE;
187 ipn->in_pr[1] = IPPROTO_GRE;
188
189 pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer;
190 pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer;
191 return 0;
192 }
193
194
195 void
ipf_p_pptp_donatstate(fin,nat,pptp)196 ipf_p_pptp_donatstate(fin, nat, pptp)
197 fr_info_t *fin;
198 nat_t *nat;
199 pptp_pxy_t *pptp;
200 {
201 ipf_main_softc_t *softc = fin->fin_main_soft;
202 fr_info_t fi;
203 grehdr_t gre;
204 nat_t *nat2;
205 u_char p;
206 ip_t *ip;
207
208 ip = fin->fin_ip;
209 p = ip->ip_p;
210
211 nat2 = pptp->pptp_nat;
212 if ((nat2 == NULL) || (pptp->pptp_state == NULL)) {
213 bcopy((char *)fin, (char *)&fi, sizeof(fi));
214 bzero((char *)&gre, sizeof(gre));
215 fi.fin_fi.fi_p = IPPROTO_GRE;
216 fi.fin_fr = &pptpfr;
217 if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) ||
218 (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) {
219 fi.fin_data[0] = pptp->pptp_call[0];
220 fi.fin_data[1] = pptp->pptp_call[1];
221 } else {
222 fi.fin_data[0] = pptp->pptp_call[1];
223 fi.fin_data[1] = pptp->pptp_call[0];
224 }
225 ip = fin->fin_ip;
226 ip->ip_p = IPPROTO_GRE;
227 fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
228 fi.fin_flx |= FI_IGNORE;
229 fi.fin_dp = &gre;
230 gre.gr_flags = htons(1 << 13);
231
232 fi.fin_fi.fi_saddr = nat->nat_osrcaddr;
233 fi.fin_fi.fi_daddr = nat->nat_odstaddr;
234 }
235
236 /*
237 * Update NAT timeout/create NAT if missing.
238 */
239 if (nat2 != NULL)
240 ipf_queueback(softc->ipf_ticks, &nat2->nat_tqe);
241 else {
242 #ifdef USE_MUTEXES
243 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
244 #endif
245
246 MUTEX_ENTER(&softn->ipf_nat_new);
247 nat2 = ipf_nat_add(&fi, pptp->pptp_rule, &pptp->pptp_nat,
248 NAT_SLAVE, nat->nat_dir);
249 MUTEX_EXIT(&softn->ipf_nat_new);
250 if (nat2 != NULL) {
251 (void) ipf_nat_proto(&fi, nat2, 0);
252 MUTEX_ENTER(&nat2->nat_lock);
253 ipf_nat_update(&fi, nat2);
254 MUTEX_EXIT(&nat2->nat_lock);
255 }
256 }
257
258 READ_ENTER(&softc->ipf_state);
259 if (pptp->pptp_state != NULL) {
260 ipf_queueback(softc->ipf_ticks, &pptp->pptp_state->is_sti);
261 RWLOCK_EXIT(&softc->ipf_state);
262 } else {
263 RWLOCK_EXIT(&softc->ipf_state);
264 if (nat2 != NULL) {
265 if (nat->nat_dir == NAT_INBOUND)
266 fi.fin_fi.fi_daddr = nat2->nat_ndstaddr;
267 else
268 fi.fin_fi.fi_saddr = nat2->nat_osrcaddr;
269 }
270 fi.fin_ifp = NULL;
271 (void) ipf_state_add(softc, &fi, &pptp->pptp_state, 0);
272 }
273 ip->ip_p = p;
274 return;
275 }
276
277
278 /*
279 * Try and build up the next PPTP message in the TCP stream and if we can
280 * build it up completely (fits in our buffer) then pass it off to the message
281 * parsing function.
282 */
283 int
ipf_p_pptp_nextmessage(fin,nat,pptp,rev)284 ipf_p_pptp_nextmessage(fin, nat, pptp, rev)
285 fr_info_t *fin;
286 nat_t *nat;
287 pptp_pxy_t *pptp;
288 int rev;
289 {
290 static const char *funcname = "ipf_p_pptp_nextmessage";
291 pptp_side_t *pptps;
292 u_32_t start, end;
293 pptp_hdr_t *hdr;
294 tcphdr_t *tcp;
295 int dlen, off;
296 u_short len;
297 char *msg;
298
299 tcp = fin->fin_dp;
300 dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
301 start = ntohl(tcp->th_seq);
302 pptps = &pptp->pptp_side[rev];
303 off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) +
304 fin->fin_ipoff;
305
306 if (dlen <= 0)
307 return 0;
308 /*
309 * If the complete data packet is before what we expect to see
310 * "next", just ignore it as the chances are we've already seen it.
311 * The next if statement following this one really just causes packets
312 * ahead of what we've seen to be dropped, implying that something in
313 * the middle went missing and we want to see that first.
314 */
315 end = start + dlen;
316 if (pptps->pptps_next > end && pptps->pptps_next > start)
317 return 0;
318
319 if (pptps->pptps_next != start) {
320 if (ipf_p_pptp_debug > 5)
321 printf("%s: next (%x) != start (%x)\n", funcname,
322 pptps->pptps_next, start);
323 return -1;
324 }
325
326 msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2);
327
328 while (dlen > 0) {
329 off += pptps->pptps_bytes;
330 if (pptps->pptps_gothdr == 0) {
331 /*
332 * PPTP has an 8 byte header that inclues the cookie.
333 * The start of every message should include one and
334 * it should match 1a2b3c4d. Byte order is ignored,
335 * deliberately, when printing out the error.
336 */
337 len = MIN(8 - pptps->pptps_bytes, dlen);
338 COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
339 pptps->pptps_bytes += len;
340 pptps->pptps_wptr += len;
341 hdr = (pptp_hdr_t *)pptps->pptps_buffer;
342 if (pptps->pptps_bytes == 8) {
343 pptps->pptps_next += 8;
344 if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) {
345 if (ipf_p_pptp_debug > 1)
346 printf("%s: bad cookie (%x)\n",
347 funcname,
348 hdr->pptph_cookie);
349 return -1;
350 }
351 }
352 dlen -= len;
353 msg += len;
354 off += len;
355
356 pptps->pptps_gothdr = 1;
357 len = ntohs(hdr->pptph_len);
358 pptps->pptps_len = len;
359 pptps->pptps_nexthdr += len;
360
361 /*
362 * If a message is too big for the buffer, just set
363 * the fields for the next message to come along.
364 * The messages defined in RFC 2637 will not exceed
365 * 512 bytes (in total length) so this is likely a
366 * bad data packet, anyway.
367 */
368 if (len > sizeof(pptps->pptps_buffer)) {
369 if (ipf_p_pptp_debug > 3)
370 printf("%s: message too big (%d)\n",
371 funcname, len);
372 pptps->pptps_next = pptps->pptps_nexthdr;
373 pptps->pptps_wptr = pptps->pptps_buffer;
374 pptps->pptps_gothdr = 0;
375 pptps->pptps_bytes = 0;
376 pptps->pptps_len = 0;
377 break;
378 }
379 }
380
381 len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen);
382 COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
383 pptps->pptps_bytes += len;
384 pptps->pptps_wptr += len;
385 pptps->pptps_next += len;
386
387 if (pptps->pptps_len > pptps->pptps_bytes)
388 break;
389
390 ipf_p_pptp_message(fin, nat, pptp, pptps);
391 pptps->pptps_wptr = pptps->pptps_buffer;
392 pptps->pptps_gothdr = 0;
393 pptps->pptps_bytes = 0;
394 pptps->pptps_len = 0;
395
396 start += len;
397 msg += len;
398 dlen -= len;
399 }
400
401 return 0;
402 }
403
404
405 /*
406 * handle a complete PPTP message
407 */
408 int
ipf_p_pptp_message(fin,nat,pptp,pptps)409 ipf_p_pptp_message(fin, nat, pptp, pptps)
410 fr_info_t *fin;
411 nat_t *nat;
412 pptp_pxy_t *pptp;
413 pptp_side_t *pptps;
414 {
415 pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer;
416
417 switch (ntohs(hdr->pptph_type))
418 {
419 case PPTP_MSGTYPE_CTL :
420 ipf_p_pptp_mctl(fin, nat, pptp, pptps);
421 break;
422
423 default :
424 break;
425 }
426 return 0;
427 }
428
429
430 /*
431 * handle a complete PPTP control message
432 */
433 int
ipf_p_pptp_mctl(fin,nat,pptp,pptps)434 ipf_p_pptp_mctl(fin, nat, pptp, pptps)
435 fr_info_t *fin;
436 nat_t *nat;
437 pptp_pxy_t *pptp;
438 pptp_side_t *pptps;
439 {
440 u_short *buffer = (u_short *)(pptps->pptps_buffer);
441 pptp_side_t *pptpo;
442
443 if (pptps == &pptp->pptp_side[0])
444 pptpo = &pptp->pptp_side[1];
445 else
446 pptpo = &pptp->pptp_side[0];
447
448 /*
449 * Breakout to handle all the various messages. Most are just state
450 * transition.
451 */
452 switch (ntohs(buffer[4]))
453 {
454 case PPTP_MTCTL_STARTREQ :
455 pptps->pptps_state = PPTP_MTCTL_STARTREQ;
456 break;
457 case PPTP_MTCTL_STARTREP :
458 if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ)
459 pptps->pptps_state = PPTP_MTCTL_STARTREP;
460 break;
461 case PPTP_MTCTL_STOPREQ :
462 pptps->pptps_state = PPTP_MTCTL_STOPREQ;
463 break;
464 case PPTP_MTCTL_STOPREP :
465 if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ)
466 pptps->pptps_state = PPTP_MTCTL_STOPREP;
467 break;
468 case PPTP_MTCTL_ECHOREQ :
469 pptps->pptps_state = PPTP_MTCTL_ECHOREQ;
470 break;
471 case PPTP_MTCTL_ECHOREP :
472 if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ)
473 pptps->pptps_state = PPTP_MTCTL_ECHOREP;
474 break;
475 case PPTP_MTCTL_OUTREQ :
476 pptps->pptps_state = PPTP_MTCTL_OUTREQ;
477 break;
478 case PPTP_MTCTL_OUTREP :
479 if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) {
480 pptps->pptps_state = PPTP_MTCTL_OUTREP;
481 pptp->pptp_call[0] = buffer[7];
482 pptp->pptp_call[1] = buffer[6];
483 ipf_p_pptp_donatstate(fin, nat, pptp);
484 }
485 break;
486 case PPTP_MTCTL_INREQ :
487 pptps->pptps_state = PPTP_MTCTL_INREQ;
488 break;
489 case PPTP_MTCTL_INREP :
490 if (pptpo->pptps_state == PPTP_MTCTL_INREQ) {
491 pptps->pptps_state = PPTP_MTCTL_INREP;
492 pptp->pptp_call[0] = buffer[7];
493 pptp->pptp_call[1] = buffer[6];
494 ipf_p_pptp_donatstate(fin, nat, pptp);
495 }
496 break;
497 case PPTP_MTCTL_INCONNECT :
498 pptps->pptps_state = PPTP_MTCTL_INCONNECT;
499 break;
500 case PPTP_MTCTL_CLEAR :
501 pptps->pptps_state = PPTP_MTCTL_CLEAR;
502 break;
503 case PPTP_MTCTL_DISCONNECT :
504 pptps->pptps_state = PPTP_MTCTL_DISCONNECT;
505 break;
506 case PPTP_MTCTL_WANERROR :
507 pptps->pptps_state = PPTP_MTCTL_WANERROR;
508 break;
509 case PPTP_MTCTL_LINKINFO :
510 pptps->pptps_state = PPTP_MTCTL_LINKINFO;
511 break;
512 }
513
514 return 0;
515 }
516
517
518 /*
519 * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if
520 * we can. If they have disappeared, recreate them.
521 */
522 int
ipf_p_pptp_inout(arg,fin,aps,nat)523 ipf_p_pptp_inout(arg, fin, aps, nat)
524 void *arg;
525 fr_info_t *fin;
526 ap_session_t *aps;
527 nat_t *nat;
528 {
529 pptp_pxy_t *pptp;
530 tcphdr_t *tcp;
531 int rev;
532
533 if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
534 rev = 1;
535 else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
536 rev = 1;
537 else
538 rev = 0;
539
540 tcp = (tcphdr_t *)fin->fin_dp;
541 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) {
542 pptp = (pptp_pxy_t *)aps->aps_data;
543 pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack);
544 pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack);
545 pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1;
546 pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1;
547 }
548 return ipf_p_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
549 rev);
550 }
551
552
553 /*
554 * clean up after ourselves.
555 */
556 void
ipf_p_pptp_del(softc,aps)557 ipf_p_pptp_del(softc, aps)
558 ipf_main_softc_t *softc;
559 ap_session_t *aps;
560 {
561 pptp_pxy_t *pptp;
562
563 pptp = aps->aps_data;
564
565 if (pptp != NULL) {
566 /*
567 * Don't bother changing any of the NAT structure details,
568 * *_del() is on a callback from aps_free(), from nat_delete()
569 */
570
571 READ_ENTER(&softc->ipf_state);
572 if (pptp->pptp_state != NULL) {
573 ipf_state_setpending(softc, pptp->pptp_state);
574 }
575 RWLOCK_EXIT(&softc->ipf_state);
576
577 if (pptp->pptp_nat != NULL)
578 ipf_nat_setpending(softc, pptp->pptp_nat);
579 pptp->pptp_rule->in_flags |= IPN_DELETE;
580 ipf_nat_rule_deref(softc, &pptp->pptp_rule);
581 }
582 }
583