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