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
12 #define IPF_PPTP_PROXY
14 typedef struct pptp_hdr
{
20 #define PPTP_MSGTYPE_CTL 1
21 #define PPTP_MTCTL_STARTREQ 1
22 #define PPTP_MTCTL_STARTREP 2
23 #define PPTP_MTCTL_STOPREQ 3
24 #define PPTP_MTCTL_STOPREP 4
25 #define PPTP_MTCTL_ECHOREQ 5
26 #define PPTP_MTCTL_ECHOREP 6
27 #define PPTP_MTCTL_OUTREQ 7
28 #define PPTP_MTCTL_OUTREP 8
29 #define PPTP_MTCTL_INREQ 9
30 #define PPTP_MTCTL_INREP 10
31 #define PPTP_MTCTL_INCONNECT 11
32 #define PPTP_MTCTL_CLEAR 12
33 #define PPTP_MTCTL_DISCONNECT 13
34 #define PPTP_MTCTL_WANERROR 14
35 #define PPTP_MTCTL_LINKINFO 15
38 int ippr_pptp_init
__P((void));
39 void ippr_pptp_fini
__P((void));
40 int ippr_pptp_new
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
41 void ippr_pptp_del
__P((ap_session_t
*));
42 int ippr_pptp_inout
__P((fr_info_t
*, ap_session_t
*, nat_t
*));
43 void ippr_pptp_donatstate
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*));
44 int ippr_pptp_message
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, pptp_side_t
*));
45 int ippr_pptp_nextmessage
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, int));
46 int ippr_pptp_mctl
__P((fr_info_t
*, nat_t
*, pptp_pxy_t
*, pptp_side_t
*));
48 static frentry_t pptpfr
;
50 int pptp_proxy_init
= 0;
51 int ippr_pptp_debug
= 0;
52 int ippr_pptp_gretimeout
= IPF_TTLVAL(120); /* 2 minutes */
56 * PPTP application proxy initialization.
60 bzero((char *)&pptpfr
, sizeof(pptpfr
));
62 pptpfr
.fr_age
[0] = ippr_pptp_gretimeout
;
63 pptpfr
.fr_age
[1] = ippr_pptp_gretimeout
;
64 pptpfr
.fr_flags
= FR_OUTQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
;
65 MUTEX_INIT(&pptpfr
.fr_lock
, "PPTP proxy rule lock");
74 if (pptp_proxy_init
== 1) {
75 MUTEX_DESTROY(&pptpfr
.fr_lock
);
82 * Setup for a new PPTP proxy.
84 * NOTE: The printf's are broken up with %s in them to prevent them being
85 * optimised into puts statements on FreeBSD (this doesn't exist in the kernel)
87 int ippr_pptp_new(fin
, aps
, nat
)
98 if (nat_outlookup(fin
, 0, IPPROTO_GRE
, nat
->nat_inip
,
99 ip
->ip_dst
) != NULL
) {
100 if (ippr_pptp_debug
> 0)
101 printf("ippr_pptp_new: GRE session %s\n",
106 aps
->aps_psiz
= sizeof(*pptp
);
107 KMALLOCS(aps
->aps_data
, pptp_pxy_t
*, sizeof(*pptp
));
108 if (aps
->aps_data
== NULL
) {
109 if (ippr_pptp_debug
> 0)
110 printf("ippr_pptp_new: malloc for aps_data %s\n",
116 * Create NAT rule against which the tunnel/transport mapping is
117 * created. This is required because the current NAT rule does not
118 * describe GRE but TCP instead.
120 pptp
= aps
->aps_data
;
121 bzero((char *)pptp
, sizeof(*pptp
));
122 ipn
= &pptp
->pptp_rule
;
123 ipn
->in_ifps
[0] = fin
->fin_ifp
;
128 if (nat
->nat_dir
== NAT_OUTBOUND
) {
129 ipn
->in_nip
= ntohl(nat
->nat_outip
.s_addr
);
130 ipn
->in_outip
= fin
->fin_saddr
;
131 ipn
->in_redir
= NAT_MAP
;
132 } else if (nat
->nat_dir
== NAT_INBOUND
) {
134 ipn
->in_outip
= nat
->nat_outip
.s_addr
;
135 ipn
->in_redir
= NAT_REDIRECT
;
137 ipn
->in_inip
= nat
->nat_inip
.s_addr
;
138 ipn
->in_inmsk
= 0xffffffff;
139 ipn
->in_outmsk
= 0xffffffff;
140 ipn
->in_srcip
= fin
->fin_saddr
;
141 ipn
->in_srcmsk
= 0xffffffff;
142 bcopy(nat
->nat_ptr
->in_ifnames
[0], ipn
->in_ifnames
[0],
143 sizeof(ipn
->in_ifnames
[0]));
144 ipn
->in_p
= IPPROTO_GRE
;
146 pptp
->pptp_side
[0].pptps_wptr
= pptp
->pptp_side
[0].pptps_buffer
;
147 pptp
->pptp_side
[1].pptps_wptr
= pptp
->pptp_side
[1].pptps_buffer
;
152 void ippr_pptp_donatstate(fin
, nat
, pptp
)
166 nat2
= pptp
->pptp_nat
;
167 if ((nat2
== NULL
) || (pptp
->pptp_state
== NULL
)) {
168 bcopy((char *)fin
, (char *)&fi
, sizeof(fi
));
169 bzero((char *)&gre
, sizeof(gre
));
170 fi
.fin_fi
.fi_p
= IPPROTO_GRE
;
172 if ((nat
->nat_dir
== NAT_OUTBOUND
&& fin
->fin_out
) ||
173 (nat
->nat_dir
== NAT_INBOUND
&& !fin
->fin_out
)) {
174 fi
.fin_data
[0] = pptp
->pptp_call
[0];
175 fi
.fin_data
[1] = pptp
->pptp_call
[1];
177 fi
.fin_data
[0] = pptp
->pptp_call
[1];
178 fi
.fin_data
[1] = pptp
->pptp_call
[0];
181 ip
->ip_p
= IPPROTO_GRE
;
182 fi
.fin_flx
&= ~(FI_TCPUDP
|FI_STATE
|FI_FRAG
);
183 fi
.fin_flx
|= FI_IGNORE
;
185 gre
.gr_flags
= htons(1 << 13);
186 if (fin
->fin_out
&& nat
->nat_dir
== NAT_INBOUND
) {
187 fi
.fin_fi
.fi_saddr
= fin
->fin_fi
.fi_daddr
;
188 fi
.fin_fi
.fi_daddr
= nat
->nat_outip
.s_addr
;
189 } else if (!fin
->fin_out
&& nat
->nat_dir
== NAT_OUTBOUND
) {
190 fi
.fin_fi
.fi_saddr
= nat
->nat_inip
.s_addr
;
191 fi
.fin_fi
.fi_daddr
= fin
->fin_fi
.fi_saddr
;
196 * Update NAT timeout/create NAT if missing.
199 fr_queueback(&nat2
->nat_tqe
);
201 MUTEX_ENTER(&ipf_nat_new
);
202 nat2
= nat_new(&fi
, &pptp
->pptp_rule
, &pptp
->pptp_nat
,
203 NAT_SLAVE
, nat
->nat_dir
);
204 MUTEX_EXIT(&ipf_nat_new
);
205 pptp
->pptp_nat
= nat2
;
207 (void) nat_proto(&fi
, nat2
, 0);
208 MUTEX_ENTER(&nat2
->nat_lock
);
209 nat_update(&fi
, nat2
);
210 MUTEX_EXIT(&nat2
->nat_lock
);
214 READ_ENTER(&ipf_state
);
215 if (pptp
->pptp_state
!= NULL
) {
216 fr_queueback(&pptp
->pptp_state
->is_sti
);
217 RWLOCK_EXIT(&ipf_state
);
219 RWLOCK_EXIT(&ipf_state
);
221 if (nat
->nat_dir
== NAT_INBOUND
)
222 fi
.fin_fi
.fi_daddr
= nat2
->nat_inip
.s_addr
;
224 fi
.fin_fi
.fi_saddr
= nat2
->nat_inip
.s_addr
;
227 pptp
->pptp_state
= fr_addstate(&fi
, &pptp
->pptp_state
,
236 * Try and build up the next PPTP message in the TCP stream and if we can
237 * build it up completely (fits in our buffer) then pass it off to the message
240 int ippr_pptp_nextmessage(fin
, nat
, pptp
, rev
)
246 static const char *funcname
= "ippr_pptp_nextmessage";
256 dlen
= fin
->fin_dlen
- (TCP_OFF(tcp
) << 2);
257 start
= ntohl(tcp
->th_seq
);
258 pptps
= &pptp
->pptp_side
[rev
];
259 off
= (char *)tcp
- (char *)fin
->fin_ip
+ (TCP_OFF(tcp
) << 2) +
265 * If the complete data packet is before what we expect to see
266 * "next", just ignore it as the chances are we've already seen it.
267 * The next if statement following this one really just causes packets
268 * ahead of what we've seen to be dropped, implying that something in
269 * the middle went missing and we want to see that first.
272 if (pptps
->pptps_next
> end
&& pptps
->pptps_next
> start
)
275 if (pptps
->pptps_next
!= start
) {
276 if (ippr_pptp_debug
> 5)
277 printf("%s: next (%x) != start (%x)\n", funcname
,
278 pptps
->pptps_next
, start
);
282 msg
= (char *)fin
->fin_dp
+ (TCP_OFF(tcp
) << 2);
285 off
+= pptps
->pptps_bytes
;
286 if (pptps
->pptps_gothdr
== 0) {
288 * PPTP has an 8 byte header that inclues the cookie.
289 * The start of every message should include one and
290 * it should match 1a2b3c4d. Byte order is ignored,
291 * deliberately, when printing out the error.
293 len
= MIN(8 - pptps
->pptps_bytes
, dlen
);
294 COPYDATA(fin
->fin_m
, off
, len
, pptps
->pptps_wptr
);
295 pptps
->pptps_bytes
+= len
;
296 pptps
->pptps_wptr
+= len
;
297 hdr
= (pptp_hdr_t
*)pptps
->pptps_buffer
;
298 if (pptps
->pptps_bytes
== 8) {
299 pptps
->pptps_next
+= 8;
300 if (ntohl(hdr
->pptph_cookie
) != 0x1a2b3c4d) {
301 if (ippr_pptp_debug
> 1)
302 printf("%s: bad cookie (%x)\n",
312 pptps
->pptps_gothdr
= 1;
313 len
= ntohs(hdr
->pptph_len
);
314 pptps
->pptps_len
= len
;
315 pptps
->pptps_nexthdr
+= len
;
318 * If a message is too big for the buffer, just set
319 * the fields for the next message to come along.
320 * The messages defined in RFC 2637 will not exceed
321 * 512 bytes (in total length) so this is likely a
322 * bad data packet, anyway.
324 if (len
> sizeof(pptps
->pptps_buffer
)) {
325 if (ippr_pptp_debug
> 3)
326 printf("%s: message too big (%d)\n",
328 pptps
->pptps_next
= pptps
->pptps_nexthdr
;
329 pptps
->pptps_wptr
= pptps
->pptps_buffer
;
330 pptps
->pptps_gothdr
= 0;
331 pptps
->pptps_bytes
= 0;
332 pptps
->pptps_len
= 0;
337 len
= MIN(pptps
->pptps_len
- 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 pptps
->pptps_next
+= len
;
343 if (pptps
->pptps_len
> pptps
->pptps_bytes
)
346 ippr_pptp_message(fin
, nat
, pptp
, pptps
);
347 pptps
->pptps_wptr
= pptps
->pptps_buffer
;
348 pptps
->pptps_gothdr
= 0;
349 pptps
->pptps_bytes
= 0;
350 pptps
->pptps_len
= 0;
362 * handle a complete PPTP message
364 int ippr_pptp_message(fin
, nat
, pptp
, pptps
)
370 pptp_hdr_t
*hdr
= (pptp_hdr_t
*)pptps
->pptps_buffer
;
372 switch (ntohs(hdr
->pptph_type
))
374 case PPTP_MSGTYPE_CTL
:
375 ippr_pptp_mctl(fin
, nat
, pptp
, pptps
);
386 * handle a complete PPTP control message
388 int ippr_pptp_mctl(fin
, nat
, pptp
, pptps
)
394 u_short
*buffer
= (u_short
*)(pptps
->pptps_buffer
);
397 if (pptps
== &pptp
->pptp_side
[0])
398 pptpo
= &pptp
->pptp_side
[1];
400 pptpo
= &pptp
->pptp_side
[0];
403 * Breakout to handle all the various messages. Most are just state
406 switch (ntohs(buffer
[4]))
408 case PPTP_MTCTL_STARTREQ
:
409 pptps
->pptps_state
= PPTP_MTCTL_STARTREQ
;
411 case PPTP_MTCTL_STARTREP
:
412 if (pptpo
->pptps_state
== PPTP_MTCTL_STARTREQ
)
413 pptps
->pptps_state
= PPTP_MTCTL_STARTREP
;
415 case PPTP_MTCTL_STOPREQ
:
416 pptps
->pptps_state
= PPTP_MTCTL_STOPREQ
;
418 case PPTP_MTCTL_STOPREP
:
419 if (pptpo
->pptps_state
== PPTP_MTCTL_STOPREQ
)
420 pptps
->pptps_state
= PPTP_MTCTL_STOPREP
;
422 case PPTP_MTCTL_ECHOREQ
:
423 pptps
->pptps_state
= PPTP_MTCTL_ECHOREQ
;
425 case PPTP_MTCTL_ECHOREP
:
426 if (pptpo
->pptps_state
== PPTP_MTCTL_ECHOREQ
)
427 pptps
->pptps_state
= PPTP_MTCTL_ECHOREP
;
429 case PPTP_MTCTL_OUTREQ
:
430 pptps
->pptps_state
= PPTP_MTCTL_OUTREQ
;
432 case PPTP_MTCTL_OUTREP
:
433 if (pptpo
->pptps_state
== PPTP_MTCTL_OUTREQ
) {
434 pptps
->pptps_state
= PPTP_MTCTL_OUTREP
;
435 pptp
->pptp_call
[0] = buffer
[7];
436 pptp
->pptp_call
[1] = buffer
[6];
437 ippr_pptp_donatstate(fin
, nat
, pptp
);
440 case PPTP_MTCTL_INREQ
:
441 pptps
->pptps_state
= PPTP_MTCTL_INREQ
;
443 case PPTP_MTCTL_INREP
:
444 if (pptpo
->pptps_state
== PPTP_MTCTL_INREQ
) {
445 pptps
->pptps_state
= PPTP_MTCTL_INREP
;
446 pptp
->pptp_call
[0] = buffer
[7];
447 pptp
->pptp_call
[1] = buffer
[6];
448 ippr_pptp_donatstate(fin
, nat
, pptp
);
451 case PPTP_MTCTL_INCONNECT
:
452 pptps
->pptps_state
= PPTP_MTCTL_INCONNECT
;
454 case PPTP_MTCTL_CLEAR
:
455 pptps
->pptps_state
= PPTP_MTCTL_CLEAR
;
457 case PPTP_MTCTL_DISCONNECT
:
458 pptps
->pptps_state
= PPTP_MTCTL_DISCONNECT
;
460 case PPTP_MTCTL_WANERROR
:
461 pptps
->pptps_state
= PPTP_MTCTL_WANERROR
;
463 case PPTP_MTCTL_LINKINFO
:
464 pptps
->pptps_state
= PPTP_MTCTL_LINKINFO
;
473 * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if
474 * we can. If they have disappeared, recreate them.
476 int ippr_pptp_inout(fin
, aps
, nat
)
485 if ((fin
->fin_out
== 1) && (nat
->nat_dir
== NAT_INBOUND
))
487 else if ((fin
->fin_out
== 0) && (nat
->nat_dir
== NAT_OUTBOUND
))
492 tcp
= (tcphdr_t
*)fin
->fin_dp
;
493 if ((tcp
->th_flags
& TH_OPENING
) == TH_OPENING
) {
494 pptp
= (pptp_pxy_t
*)aps
->aps_data
;
495 pptp
->pptp_side
[1 - rev
].pptps_next
= ntohl(tcp
->th_ack
);
496 pptp
->pptp_side
[1 - rev
].pptps_nexthdr
= ntohl(tcp
->th_ack
);
497 pptp
->pptp_side
[rev
].pptps_next
= ntohl(tcp
->th_seq
) + 1;
498 pptp
->pptp_side
[rev
].pptps_nexthdr
= ntohl(tcp
->th_seq
) + 1;
500 return ippr_pptp_nextmessage(fin
, nat
, (pptp_pxy_t
*)aps
->aps_data
,
506 * clean up after ourselves.
508 void ippr_pptp_del(aps
)
513 pptp
= aps
->aps_data
;
517 * Don't bother changing any of the NAT structure details,
518 * *_del() is on a callback from aps_free(), from nat_delete()
521 READ_ENTER(&ipf_state
);
522 if (pptp
->pptp_state
!= NULL
) {
523 pptp
->pptp_state
->is_die
= fr_ticks
+ 1;
524 pptp
->pptp_state
->is_me
= NULL
;
525 fr_queuefront(&pptp
->pptp_state
->is_sti
);
527 RWLOCK_EXIT(&ipf_state
);
529 pptp
->pptp_state
= NULL
;
530 pptp
->pptp_nat
= NULL
;