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