4 * Copyright (C) 2002-2003 by Darren Reed
6 * Simple PPTP transparent proxy for in-kernel use. For use with the NAT
9 * Id: ip_pptp_pxy.c,v 2.10.2.18 2008/11/06 21:18:36 darrenr Exp
13 #include <sys/cdefs.h>
14 __KERNEL_RCSID(1, "$NetBSD$");
16 #define IPF_PPTP_PROXY
18 typedef struct pptp_hdr
{
24 #define PPTP_MSGTYPE_CTL 1
25 #define PPTP_MTCTL_STARTREQ 1
26 #define PPTP_MTCTL_STARTREP 2
27 #define PPTP_MTCTL_STOPREQ 3
28 #define PPTP_MTCTL_STOPREP 4
29 #define PPTP_MTCTL_ECHOREQ 5
30 #define PPTP_MTCTL_ECHOREP 6
31 #define PPTP_MTCTL_OUTREQ 7
32 #define PPTP_MTCTL_OUTREP 8
33 #define PPTP_MTCTL_INREQ 9
34 #define PPTP_MTCTL_INREP 10
35 #define PPTP_MTCTL_INCONNECT 11
36 #define PPTP_MTCTL_CLEAR 12
37 #define PPTP_MTCTL_DISCONNECT 13
38 #define PPTP_MTCTL_WANERROR 14
39 #define PPTP_MTCTL_LINKINFO 15
42 int ippr_pptp_init
__P((void));
43 void ippr_pptp_fini
__P((void));
44 int ippr_pptp_new
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
45 void ippr_pptp_del
__P((ap_session_t
*));
46 int ippr_pptp_inout
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
47 void ippr_pptp_donatstate
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*));
48 int ippr_pptp_message
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, pptp_side_t
*));
49 int ippr_pptp_nextmessage
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, int));
50 int ippr_pptp_mctl
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, pptp_side_t
*));
52 static frentry_t pptpfr
;
54 int pptp_proxy_init
= 0;
55 int ippr_pptp_debug
= 0;
56 int ippr_pptp_gretimeout
= IPF_TTLVAL(120); /* 2 minutes */
60 * PPTP application proxy initialization.
64 bzero((char *)&pptpfr
, sizeof(pptpfr
));
66 pptpfr
.fr_age
[0] = ippr_pptp_gretimeout
;
67 pptpfr
.fr_age
[1] = ippr_pptp_gretimeout
;
68 pptpfr
.fr_flags
= FR_OUTQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
69 MUTEX_INIT(&pptpfr
.fr_lock
, "PPTP proxy rule lock");
78 if (pptp_proxy_init
== 1) {
79 MUTEX_DESTROY(&pptpfr
.fr_lock
);
86 * Setup for a new PPTP proxy.
88 * NOTE: The printf's are broken up with %s in them to prevent them being
89 * optimised into puts statements on FreeBSD (this doesn't exist in the kernel)
91 int ippr_pptp_new(fin
, aps
, nat
)
102 if (nat_outlookup(fin
, 0, IPPROTO_GRE
, nat
->nat_inip
,
103 ip
->ip_dst
) != NULL
) {
104 if (ippr_pptp_debug
> 0)
105 printf("ippr_pptp_new: GRE session %s\n",
110 aps
->aps_psiz
= sizeof(*pptp
);
111 KMALLOCS(aps
->aps_data
, pptp_pxy_t
*, sizeof(*pptp
));
112 if (aps
->aps_data
== NULL
) {
113 if (ippr_pptp_debug
> 0)
114 printf("ippr_pptp_new: malloc for aps_data %s\n",
120 * Create NAT rule against which the tunnel/transport mapping is
121 * created. This is required because the current NAT rule does not
122 * describe GRE but TCP instead.
124 pptp
= aps
->aps_data
;
125 bzero((char *)pptp
, sizeof(*pptp
));
126 ipn
= &pptp
->pptp_rule
;
127 ipn
->in_ifps
[0] = fin
->fin_ifp
;
132 if (nat
->nat_dir
== NAT_OUTBOUND
) {
133 ipn
->in_nip
= ntohl(nat
->nat_outip
.s_addr
);
134 ipn
->in_outip
= fin
->fin_saddr
;
135 ipn
->in_redir
= NAT_MAP
;
136 } else if (nat
->nat_dir
== NAT_INBOUND
) {
138 ipn
->in_outip
= nat
->nat_outip
.s_addr
;
139 ipn
->in_redir
= NAT_REDIRECT
;
141 ipn
->in_inip
= nat
->nat_inip
.s_addr
;
142 ipn
->in_inmsk
= 0xffffffff;
143 ipn
->in_outmsk
= 0xffffffff;
144 ipn
->in_srcip
= fin
->fin_saddr
;
145 ipn
->in_srcmsk
= 0xffffffff;
146 bcopy(nat
->nat_ptr
->in_ifnames
[0], ipn
->in_ifnames
[0],
147 sizeof(ipn
->in_ifnames
[0]));
148 ipn
->in_p
= IPPROTO_GRE
;
150 pptp
->pptp_side
[0].pptps_wptr
= pptp
->pptp_side
[0].pptps_buffer
;
151 pptp
->pptp_side
[1].pptps_wptr
= pptp
->pptp_side
[1].pptps_buffer
;
156 void ippr_pptp_donatstate(fin
, nat
, pptp
)
170 nat2
= pptp
->pptp_nat
;
171 if ((nat2
== NULL
) || (pptp
->pptp_state
== NULL
)) {
172 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
173 bzero((char *)&gre
, sizeof(gre
));
174 fi
.fin_fi
.fi_p
= IPPROTO_GRE
;
176 if ((nat
->nat_dir
== NAT_OUTBOUND
&& fin
->fin_out
) ||
177 (nat
->nat_dir
== NAT_INBOUND
&& !fin
->fin_out
)) {
178 fi
.fin_data
[0] = pptp
->pptp_call
[0];
179 fi
.fin_data
[1] = pptp
->pptp_call
[1];
181 fi
.fin_data
[0] = pptp
->pptp_call
[1];
182 fi
.fin_data
[1] = pptp
->pptp_call
[0];
185 ip
->ip_p
= IPPROTO_GRE
;
186 fi
.fin_flx
&= ~(FI_TCPUDP
|FI_STATE
|FI_FRAG
);
187 fi
.fin_flx
|= FI_IGNORE
;
189 gre
.gr_flags
= htons(1 << 13);
190 if (fin
->fin_out
&& nat
->nat_dir
== NAT_INBOUND
) {
191 fi
.fin_fi
.fi_saddr
= fin
->fin_fi
.fi_daddr
;
192 fi
.fin_fi
.fi_daddr
= nat
->nat_outip
.s_addr
;
193 } else if (!fin
->fin_out
&& nat
->nat_dir
== NAT_OUTBOUND
) {
194 fi
.fin_fi
.fi_saddr
= nat
->nat_inip
.s_addr
;
195 fi
.fin_fi
.fi_daddr
= fin
->fin_fi
.fi_saddr
;
200 * Update NAT timeout/create NAT if missing.
203 fr_queueback(&nat2
->nat_tqe
);
205 MUTEX_ENTER(&ipf_nat_new
);
206 nat2
= nat_new(&fi
, &pptp
->pptp_rule
, &pptp
->pptp_nat
,
207 NAT_SLAVE
, nat
->nat_dir
);
208 MUTEX_EXIT(&ipf_nat_new
);
209 pptp
->pptp_nat
= nat2
;
211 (void) nat_proto(&fi
, nat2
, 0);
212 MUTEX_ENTER(&nat2
->nat_lock
);
213 nat_update(&fi
, nat2
);
214 MUTEX_EXIT(&nat2
->nat_lock
);
218 READ_ENTER(&ipf_state
);
219 if (pptp
->pptp_state
!= NULL
) {
220 fr_queueback(&pptp
->pptp_state
->is_sti
);
221 RWLOCK_EXIT(&ipf_state
);
223 RWLOCK_EXIT(&ipf_state
);
225 if (nat
->nat_dir
== NAT_INBOUND
)
226 fi
.fin_fi
.fi_daddr
= nat2
->nat_inip
.s_addr
;
228 fi
.fin_fi
.fi_saddr
= nat2
->nat_inip
.s_addr
;
231 pptp
->pptp_state
= fr_addstate(&fi
, &pptp
->pptp_state
,
240 * Try and build up the next PPTP message in the TCP stream and if we can
241 * build it up completely (fits in our buffer) then pass it off to the message
244 int ippr_pptp_nextmessage(fin
, nat
, pptp
, rev
)
250 static const char *funcname
= "ippr_pptp_nextmessage";
260 dlen
= fin
->fin_dlen
- (TCP_OFF(tcp
) << 2);
261 start
= ntohl(tcp
->th_seq
);
262 pptps
= &pptp
->pptp_side
[rev
];
263 off
= (char *)tcp
- (char *)fin
->fin_ip
+ (TCP_OFF(tcp
) << 2) +
269 * If the complete data packet is before what we expect to see
270 * "next", just ignore it as the chances are we've already seen it.
271 * The next if statement following this one really just causes packets
272 * ahead of what we've seen to be dropped, implying that something in
273 * the middle went missing and we want to see that first.
276 if (pptps
->pptps_next
> end
&& pptps
->pptps_next
> start
)
279 if (pptps
->pptps_next
!= start
) {
280 if (ippr_pptp_debug
> 5)
281 printf("%s: next (%x) != start (%x)\n", funcname
,
282 pptps
->pptps_next
, start
);
286 msg
= (char *)fin
->fin_dp
+ (TCP_OFF(tcp
) << 2);
289 off
+= pptps
->pptps_bytes
;
290 if (pptps
->pptps_gothdr
== 0) {
292 * PPTP has an 8 byte header that inclues the cookie.
293 * The start of every message should include one and
294 * it should match 1a2b3c4d. Byte order is ignored,
295 * deliberately, when printing out the error.
297 len
= MIN(8 - pptps
->pptps_bytes
, dlen
);
298 COPYDATA(fin
->fin_m
, off
, len
, pptps
->pptps_wptr
);
299 pptps
->pptps_bytes
+= len
;
300 pptps
->pptps_wptr
+= len
;
301 hdr
= (pptp_hdr_t
*)pptps
->pptps_buffer
;
302 if (pptps
->pptps_bytes
== 8) {
303 pptps
->pptps_next
+= 8;
304 if (ntohl(hdr
->pptph_cookie
) != 0x1a2b3c4d) {
305 if (ippr_pptp_debug
> 1)
306 printf("%s: bad cookie (%x)\n",
316 pptps
->pptps_gothdr
= 1;
317 len
= ntohs(hdr
->pptph_len
);
318 pptps
->pptps_len
= len
;
319 pptps
->pptps_nexthdr
+= len
;
322 * If a message is too big for the buffer, just set
323 * the fields for the next message to come along.
324 * The messages defined in RFC 2637 will not exceed
325 * 512 bytes (in total length) so this is likely a
326 * bad data packet, anyway.
328 if (len
> sizeof(pptps
->pptps_buffer
)) {
329 if (ippr_pptp_debug
> 3)
330 printf("%s: message too big (%d)\n",
332 pptps
->pptps_next
= pptps
->pptps_nexthdr
;
333 pptps
->pptps_wptr
= pptps
->pptps_buffer
;
334 pptps
->pptps_gothdr
= 0;
335 pptps
->pptps_bytes
= 0;
336 pptps
->pptps_len
= 0;
341 len
= MIN(pptps
->pptps_len
- pptps
->pptps_bytes
, dlen
);
342 COPYDATA(fin
->fin_m
, off
, len
, pptps
->pptps_wptr
);
343 pptps
->pptps_bytes
+= len
;
344 pptps
->pptps_wptr
+= len
;
345 pptps
->pptps_next
+= len
;
347 if (pptps
->pptps_len
> pptps
->pptps_bytes
)
350 ippr_pptp_message(fin
, nat
, pptp
, pptps
);
351 pptps
->pptps_wptr
= pptps
->pptps_buffer
;
352 pptps
->pptps_gothdr
= 0;
353 pptps
->pptps_bytes
= 0;
354 pptps
->pptps_len
= 0;
366 * handle a complete PPTP message
368 int ippr_pptp_message(fin
, nat
, pptp
, pptps
)
374 pptp_hdr_t
*hdr
= (pptp_hdr_t
*)pptps
->pptps_buffer
;
376 switch (ntohs(hdr
->pptph_type
))
378 case PPTP_MSGTYPE_CTL
:
379 ippr_pptp_mctl(fin
, nat
, pptp
, pptps
);
390 * handle a complete PPTP control message
392 int ippr_pptp_mctl(fin
, nat
, pptp
, pptps
)
398 u_short
*buffer
= (u_short
*)(pptps
->pptps_buffer
);
401 if (pptps
== &pptp
->pptp_side
[0])
402 pptpo
= &pptp
->pptp_side
[1];
404 pptpo
= &pptp
->pptp_side
[0];
407 * Breakout to handle all the various messages. Most are just state
410 switch (ntohs(buffer
[4]))
412 case PPTP_MTCTL_STARTREQ
:
413 pptps
->pptps_state
= PPTP_MTCTL_STARTREQ
;
415 case PPTP_MTCTL_STARTREP
:
416 if (pptpo
->pptps_state
== PPTP_MTCTL_STARTREQ
)
417 pptps
->pptps_state
= PPTP_MTCTL_STARTREP
;
419 case PPTP_MTCTL_STOPREQ
:
420 pptps
->pptps_state
= PPTP_MTCTL_STOPREQ
;
422 case PPTP_MTCTL_STOPREP
:
423 if (pptpo
->pptps_state
== PPTP_MTCTL_STOPREQ
)
424 pptps
->pptps_state
= PPTP_MTCTL_STOPREP
;
426 case PPTP_MTCTL_ECHOREQ
:
427 pptps
->pptps_state
= PPTP_MTCTL_ECHOREQ
;
429 case PPTP_MTCTL_ECHOREP
:
430 if (pptpo
->pptps_state
== PPTP_MTCTL_ECHOREQ
)
431 pptps
->pptps_state
= PPTP_MTCTL_ECHOREP
;
433 case PPTP_MTCTL_OUTREQ
:
434 pptps
->pptps_state
= PPTP_MTCTL_OUTREQ
;
436 case PPTP_MTCTL_OUTREP
:
437 if (pptpo
->pptps_state
== PPTP_MTCTL_OUTREQ
) {
438 pptps
->pptps_state
= PPTP_MTCTL_OUTREP
;
439 pptp
->pptp_call
[0] = buffer
[7];
440 pptp
->pptp_call
[1] = buffer
[6];
441 ippr_pptp_donatstate(fin
, nat
, pptp
);
444 case PPTP_MTCTL_INREQ
:
445 pptps
->pptps_state
= PPTP_MTCTL_INREQ
;
447 case PPTP_MTCTL_INREP
:
448 if (pptpo
->pptps_state
== PPTP_MTCTL_INREQ
) {
449 pptps
->pptps_state
= PPTP_MTCTL_INREP
;
450 pptp
->pptp_call
[0] = buffer
[7];
451 pptp
->pptp_call
[1] = buffer
[6];
452 ippr_pptp_donatstate(fin
, nat
, pptp
);
455 case PPTP_MTCTL_INCONNECT
:
456 pptps
->pptps_state
= PPTP_MTCTL_INCONNECT
;
458 case PPTP_MTCTL_CLEAR
:
459 pptps
->pptps_state
= PPTP_MTCTL_CLEAR
;
461 case PPTP_MTCTL_DISCONNECT
:
462 pptps
->pptps_state
= PPTP_MTCTL_DISCONNECT
;
464 case PPTP_MTCTL_WANERROR
:
465 pptps
->pptps_state
= PPTP_MTCTL_WANERROR
;
467 case PPTP_MTCTL_LINKINFO
:
468 pptps
->pptps_state
= PPTP_MTCTL_LINKINFO
;
477 * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if
478 * we can. If they have disappeared, recreate them.
480 int ippr_pptp_inout(fin
, aps
, nat
)
489 if ((fin
->fin_out
== 1) && (nat
->nat_dir
== NAT_INBOUND
))
491 else if ((fin
->fin_out
== 0) && (nat
->nat_dir
== NAT_OUTBOUND
))
496 tcp
= (tcphdr_t
*)fin
->fin_dp
;
497 if ((tcp
->th_flags
& TH_OPENING
) == TH_OPENING
) {
498 pptp
= (pptp_pxy_t
*)aps
->aps_data
;
499 pptp
->pptp_side
[1 - rev
].pptps_next
= ntohl(tcp
->th_ack
);
500 pptp
->pptp_side
[1 - rev
].pptps_nexthdr
= ntohl(tcp
->th_ack
);
501 pptp
->pptp_side
[rev
].pptps_next
= ntohl(tcp
->th_seq
) + 1;
502 pptp
->pptp_side
[rev
].pptps_nexthdr
= ntohl(tcp
->th_seq
) + 1;
504 return ippr_pptp_nextmessage(fin
, nat
, (pptp_pxy_t
*)aps
->aps_data
,
510 * clean up after ourselves.
512 void ippr_pptp_del(aps
)
517 pptp
= aps
->aps_data
;
521 * Don't bother changing any of the NAT structure details,
522 * *_del() is on a callback from aps_free(), from nat_delete()
525 READ_ENTER(&ipf_state
);
526 if (pptp
->pptp_state
!= NULL
) {
527 pptp
->pptp_state
->is_die
= fr_ticks
+ 1;
528 pptp
->pptp_state
->is_me
= NULL
;
529 fr_queuefront(&pptp
->pptp_state
->is_sti
);
531 RWLOCK_EXIT(&ipf_state
);
533 pptp
->pptp_state
= NULL
;
534 pptp
->pptp_nat
= NULL
;