1*a9643ea8Slogwang /*
2*a9643ea8Slogwang  * alias_pptp.c
3*a9643ea8Slogwang  *
4*a9643ea8Slogwang  * Copyright (c) 2000 Whistle Communications, Inc.
5*a9643ea8Slogwang  * All rights reserved.
6*a9643ea8Slogwang  *
7*a9643ea8Slogwang  * Subject to the following obligations and disclaimer of warranty, use and
8*a9643ea8Slogwang  * redistribution of this software, in source or object code forms, with or
9*a9643ea8Slogwang  * without modifications are expressly permitted by Whistle Communications;
10*a9643ea8Slogwang  * provided, however, that:
11*a9643ea8Slogwang  * 1. Any and all reproductions of the source or object code must include the
12*a9643ea8Slogwang  *    copyright notice above and the following disclaimer of warranties; and
13*a9643ea8Slogwang  * 2. No rights are granted, in any manner or form, to use Whistle
14*a9643ea8Slogwang  *    Communications, Inc. trademarks, including the mark "WHISTLE
15*a9643ea8Slogwang  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16*a9643ea8Slogwang  *    such appears in the above copyright notice or in the software.
17*a9643ea8Slogwang  *
18*a9643ea8Slogwang  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19*a9643ea8Slogwang  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20*a9643ea8Slogwang  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21*a9643ea8Slogwang  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22*a9643ea8Slogwang  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23*a9643ea8Slogwang  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24*a9643ea8Slogwang  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25*a9643ea8Slogwang  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26*a9643ea8Slogwang  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27*a9643ea8Slogwang  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28*a9643ea8Slogwang  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29*a9643ea8Slogwang  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30*a9643ea8Slogwang  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31*a9643ea8Slogwang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*a9643ea8Slogwang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33*a9643ea8Slogwang  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34*a9643ea8Slogwang  * OF SUCH DAMAGE.
35*a9643ea8Slogwang  *
36*a9643ea8Slogwang  * Author: Erik Salander <[email protected]>
37*a9643ea8Slogwang  */
38*a9643ea8Slogwang 
39*a9643ea8Slogwang #include <sys/cdefs.h>
40*a9643ea8Slogwang __FBSDID("$FreeBSD$");
41*a9643ea8Slogwang 
42*a9643ea8Slogwang /* Includes */
43*a9643ea8Slogwang #ifdef _KERNEL
44*a9643ea8Slogwang #include <sys/param.h>
45*a9643ea8Slogwang #include <sys/limits.h>
46*a9643ea8Slogwang #include <sys/kernel.h>
47*a9643ea8Slogwang #include <sys/module.h>
48*a9643ea8Slogwang #else
49*a9643ea8Slogwang #include <errno.h>
50*a9643ea8Slogwang #include <limits.h>
51*a9643ea8Slogwang #include <sys/types.h>
52*a9643ea8Slogwang #include <stdio.h>
53*a9643ea8Slogwang #endif
54*a9643ea8Slogwang 
55*a9643ea8Slogwang #include <netinet/tcp.h>
56*a9643ea8Slogwang 
57*a9643ea8Slogwang #ifdef _KERNEL
58*a9643ea8Slogwang #include <netinet/libalias/alias.h>
59*a9643ea8Slogwang #include <netinet/libalias/alias_local.h>
60*a9643ea8Slogwang #include <netinet/libalias/alias_mod.h>
61*a9643ea8Slogwang #else
62*a9643ea8Slogwang #include "alias.h"
63*a9643ea8Slogwang #include "alias_local.h"
64*a9643ea8Slogwang #include "alias_mod.h"
65*a9643ea8Slogwang #endif
66*a9643ea8Slogwang 
67*a9643ea8Slogwang #define PPTP_CONTROL_PORT_NUMBER 1723
68*a9643ea8Slogwang 
69*a9643ea8Slogwang static void
70*a9643ea8Slogwang AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *);
71*a9643ea8Slogwang 
72*a9643ea8Slogwang static void
73*a9643ea8Slogwang AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *);
74*a9643ea8Slogwang 
75*a9643ea8Slogwang static int
76*a9643ea8Slogwang AliasHandlePptpGreOut(struct libalias *, struct ip *);
77*a9643ea8Slogwang 
78*a9643ea8Slogwang static int
79*a9643ea8Slogwang AliasHandlePptpGreIn(struct libalias *, struct ip *);
80*a9643ea8Slogwang 
81*a9643ea8Slogwang static int
fingerprint(struct libalias * la,struct alias_data * ah)82*a9643ea8Slogwang fingerprint(struct libalias *la, struct alias_data *ah)
83*a9643ea8Slogwang {
84*a9643ea8Slogwang 
85*a9643ea8Slogwang 	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
86*a9643ea8Slogwang 		return (-1);
87*a9643ea8Slogwang 	if (ntohs(*ah->dport) == PPTP_CONTROL_PORT_NUMBER
88*a9643ea8Slogwang 	    || ntohs(*ah->sport) == PPTP_CONTROL_PORT_NUMBER)
89*a9643ea8Slogwang 		return (0);
90*a9643ea8Slogwang 	return (-1);
91*a9643ea8Slogwang }
92*a9643ea8Slogwang 
93*a9643ea8Slogwang static int
fingerprintgre(struct libalias * la,struct alias_data * ah)94*a9643ea8Slogwang fingerprintgre(struct libalias *la, struct alias_data *ah)
95*a9643ea8Slogwang {
96*a9643ea8Slogwang 
97*a9643ea8Slogwang 	return (0);
98*a9643ea8Slogwang }
99*a9643ea8Slogwang 
100*a9643ea8Slogwang static int
protohandlerin(struct libalias * la,struct ip * pip,struct alias_data * ah)101*a9643ea8Slogwang protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
102*a9643ea8Slogwang {
103*a9643ea8Slogwang 
104*a9643ea8Slogwang 	AliasHandlePptpIn(la, pip, ah->lnk);
105*a9643ea8Slogwang 	return (0);
106*a9643ea8Slogwang }
107*a9643ea8Slogwang 
108*a9643ea8Slogwang static int
protohandlerout(struct libalias * la,struct ip * pip,struct alias_data * ah)109*a9643ea8Slogwang protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
110*a9643ea8Slogwang {
111*a9643ea8Slogwang 
112*a9643ea8Slogwang 	AliasHandlePptpOut(la, pip, ah->lnk);
113*a9643ea8Slogwang 	return (0);
114*a9643ea8Slogwang }
115*a9643ea8Slogwang 
116*a9643ea8Slogwang static int
protohandlergrein(struct libalias * la,struct ip * pip,struct alias_data * ah)117*a9643ea8Slogwang protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
118*a9643ea8Slogwang {
119*a9643ea8Slogwang 
120*a9643ea8Slogwang 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
121*a9643ea8Slogwang 	    AliasHandlePptpGreIn(la, pip) == 0)
122*a9643ea8Slogwang 		return (0);
123*a9643ea8Slogwang 	return (-1);
124*a9643ea8Slogwang }
125*a9643ea8Slogwang 
126*a9643ea8Slogwang static int
protohandlergreout(struct libalias * la,struct ip * pip,struct alias_data * ah)127*a9643ea8Slogwang protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
128*a9643ea8Slogwang {
129*a9643ea8Slogwang 
130*a9643ea8Slogwang 	if (AliasHandlePptpGreOut(la, pip) == 0)
131*a9643ea8Slogwang 		return (0);
132*a9643ea8Slogwang 	return (-1);
133*a9643ea8Slogwang }
134*a9643ea8Slogwang 
135*a9643ea8Slogwang /* Kernel module definition. */
136*a9643ea8Slogwang struct proto_handler handlers[] = {
137*a9643ea8Slogwang 	{
138*a9643ea8Slogwang 	  .pri = 200,
139*a9643ea8Slogwang 	  .dir = IN,
140*a9643ea8Slogwang 	  .proto = TCP,
141*a9643ea8Slogwang 	  .fingerprint = &fingerprint,
142*a9643ea8Slogwang 	  .protohandler = &protohandlerin
143*a9643ea8Slogwang 	},
144*a9643ea8Slogwang 	{
145*a9643ea8Slogwang 	  .pri = 210,
146*a9643ea8Slogwang 	  .dir = OUT,
147*a9643ea8Slogwang 	  .proto = TCP,
148*a9643ea8Slogwang 	  .fingerprint = &fingerprint,
149*a9643ea8Slogwang 	  .protohandler = &protohandlerout
150*a9643ea8Slogwang 	},
151*a9643ea8Slogwang /*
152*a9643ea8Slogwang  * WATCH OUT!!! these 2 handlers NEED a priority of INT_MAX (highest possible)
153*a9643ea8Slogwang  * cause they will ALWAYS process packets, so they must be the last one
154*a9643ea8Slogwang  * in chain: look fingerprintgre() above.
155*a9643ea8Slogwang  */
156*a9643ea8Slogwang 	{
157*a9643ea8Slogwang 	  .pri = INT_MAX,
158*a9643ea8Slogwang 	  .dir = IN,
159*a9643ea8Slogwang 	  .proto = IP,
160*a9643ea8Slogwang 	  .fingerprint = &fingerprintgre,
161*a9643ea8Slogwang 	  .protohandler = &protohandlergrein
162*a9643ea8Slogwang 	},
163*a9643ea8Slogwang 	{
164*a9643ea8Slogwang 	  .pri = INT_MAX,
165*a9643ea8Slogwang 	  .dir = OUT,
166*a9643ea8Slogwang 	  .proto = IP,
167*a9643ea8Slogwang 	  .fingerprint = &fingerprintgre,
168*a9643ea8Slogwang 	  .protohandler = &protohandlergreout
169*a9643ea8Slogwang 	},
170*a9643ea8Slogwang 	{ EOH }
171*a9643ea8Slogwang };
172*a9643ea8Slogwang static int
mod_handler(module_t mod,int type,void * data)173*a9643ea8Slogwang mod_handler(module_t mod, int type, void *data)
174*a9643ea8Slogwang {
175*a9643ea8Slogwang 	int error;
176*a9643ea8Slogwang 
177*a9643ea8Slogwang 	switch (type) {
178*a9643ea8Slogwang 	case MOD_LOAD:
179*a9643ea8Slogwang 		error = 0;
180*a9643ea8Slogwang 		LibAliasAttachHandlers(handlers);
181*a9643ea8Slogwang 		break;
182*a9643ea8Slogwang 	case MOD_UNLOAD:
183*a9643ea8Slogwang 		error = 0;
184*a9643ea8Slogwang 		LibAliasDetachHandlers(handlers);
185*a9643ea8Slogwang 		break;
186*a9643ea8Slogwang 	default:
187*a9643ea8Slogwang 		error = EINVAL;
188*a9643ea8Slogwang 	}
189*a9643ea8Slogwang 	return (error);
190*a9643ea8Slogwang }
191*a9643ea8Slogwang 
192*a9643ea8Slogwang #ifdef _KERNEL
193*a9643ea8Slogwang static
194*a9643ea8Slogwang #endif
195*a9643ea8Slogwang moduledata_t alias_mod = {
196*a9643ea8Slogwang        "alias_pptp", mod_handler, NULL
197*a9643ea8Slogwang };
198*a9643ea8Slogwang 
199*a9643ea8Slogwang #ifdef	_KERNEL
200*a9643ea8Slogwang DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
201*a9643ea8Slogwang MODULE_VERSION(alias_pptp, 1);
202*a9643ea8Slogwang MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1);
203*a9643ea8Slogwang #endif
204*a9643ea8Slogwang 
205*a9643ea8Slogwang /*
206*a9643ea8Slogwang    Alias_pptp.c performs special processing for PPTP sessions under TCP.
207*a9643ea8Slogwang    Specifically, watch PPTP control messages and alias the Call ID or the
208*a9643ea8Slogwang    Peer's Call ID in the appropriate messages.  Note, PPTP requires
209*a9643ea8Slogwang    "de-aliasing" of incoming packets, this is different than any other
210*a9643ea8Slogwang    TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
211*a9643ea8Slogwang 
212*a9643ea8Slogwang    For Call IDs encountered for the first time, a PPTP alias link is created.
213*a9643ea8Slogwang    The PPTP alias link uses the Call ID in place of the original port number.
214*a9643ea8Slogwang    An alias Call ID is created.
215*a9643ea8Slogwang 
216*a9643ea8Slogwang    For this routine to work, the PPTP control messages must fit entirely
217*a9643ea8Slogwang    into a single TCP packet.  This is typically the case, but is not
218*a9643ea8Slogwang    required by the spec.
219*a9643ea8Slogwang 
220*a9643ea8Slogwang    Unlike some of the other TCP applications that are aliased (ie. FTP,
221*a9643ea8Slogwang    IRC and RTSP), the PPTP control messages that need to be aliased are
222*a9643ea8Slogwang    guaranteed to remain the same length.  The aliased Call ID is a fixed
223*a9643ea8Slogwang    length field.
224*a9643ea8Slogwang 
225*a9643ea8Slogwang    Reference: RFC 2637
226*a9643ea8Slogwang 
227*a9643ea8Slogwang    Initial version:  May, 2000 (eds)
228*a9643ea8Slogwang 
229*a9643ea8Slogwang */
230*a9643ea8Slogwang 
231*a9643ea8Slogwang /*
232*a9643ea8Slogwang  * PPTP definitions
233*a9643ea8Slogwang  */
234*a9643ea8Slogwang 
235*a9643ea8Slogwang struct grehdr {			/* Enhanced GRE header. */
236*a9643ea8Slogwang 	u_int16_t	gh_flags;	/* Flags. */
237*a9643ea8Slogwang 	u_int16_t	gh_protocol;	/* Protocol type. */
238*a9643ea8Slogwang 	u_int16_t	gh_length;	/* Payload length. */
239*a9643ea8Slogwang 	u_int16_t	gh_call_id;	/* Call ID. */
240*a9643ea8Slogwang 	u_int32_t	gh_seq_no;	/* Sequence number (optional). */
241*a9643ea8Slogwang 	u_int32_t	gh_ack_no;	/* Acknowledgment number
242*a9643ea8Slogwang 					 * (optional). */
243*a9643ea8Slogwang };
244*a9643ea8Slogwang typedef struct grehdr GreHdr;
245*a9643ea8Slogwang 
246*a9643ea8Slogwang /* The PPTP protocol ID used in the GRE 'proto' field. */
247*a9643ea8Slogwang #define PPTP_GRE_PROTO          0x880b
248*a9643ea8Slogwang 
249*a9643ea8Slogwang /* Bits that must be set a certain way in all PPTP/GRE packets. */
250*a9643ea8Slogwang #define PPTP_INIT_VALUE		((0x2001 << 16) | PPTP_GRE_PROTO)
251*a9643ea8Slogwang #define PPTP_INIT_MASK		0xef7fffff
252*a9643ea8Slogwang 
253*a9643ea8Slogwang #define PPTP_MAGIC		0x1a2b3c4d
254*a9643ea8Slogwang #define PPTP_CTRL_MSG_TYPE	1
255*a9643ea8Slogwang 
256*a9643ea8Slogwang enum {
257*a9643ea8Slogwang 	PPTP_StartCtrlConnRequest = 1,
258*a9643ea8Slogwang 	PPTP_StartCtrlConnReply = 2,
259*a9643ea8Slogwang 	PPTP_StopCtrlConnRequest = 3,
260*a9643ea8Slogwang 	PPTP_StopCtrlConnReply = 4,
261*a9643ea8Slogwang 	PPTP_EchoRequest = 5,
262*a9643ea8Slogwang 	PPTP_EchoReply = 6,
263*a9643ea8Slogwang 	PPTP_OutCallRequest = 7,
264*a9643ea8Slogwang 	PPTP_OutCallReply = 8,
265*a9643ea8Slogwang 	PPTP_InCallRequest = 9,
266*a9643ea8Slogwang 	PPTP_InCallReply = 10,
267*a9643ea8Slogwang 	PPTP_InCallConn = 11,
268*a9643ea8Slogwang 	PPTP_CallClearRequest = 12,
269*a9643ea8Slogwang 	PPTP_CallDiscNotify = 13,
270*a9643ea8Slogwang 	PPTP_WanErrorNotify = 14,
271*a9643ea8Slogwang 	PPTP_SetLinkInfo = 15
272*a9643ea8Slogwang };
273*a9643ea8Slogwang 
274*a9643ea8Slogwang  /* Message structures */
275*a9643ea8Slogwang struct pptpMsgHead {
276*a9643ea8Slogwang 	u_int16_t	length;	/* total length */
277*a9643ea8Slogwang 	u_int16_t	msgType;/* PPTP message type */
278*a9643ea8Slogwang 	u_int32_t	magic;	/* magic cookie */
279*a9643ea8Slogwang 	u_int16_t	type;	/* control message type */
280*a9643ea8Slogwang 	u_int16_t	resv0;	/* reserved */
281*a9643ea8Slogwang };
282*a9643ea8Slogwang typedef struct pptpMsgHead *PptpMsgHead;
283*a9643ea8Slogwang 
284*a9643ea8Slogwang struct pptpCodes {
285*a9643ea8Slogwang 	u_int8_t	resCode;/* Result Code */
286*a9643ea8Slogwang 	u_int8_t	errCode;/* Error Code */
287*a9643ea8Slogwang };
288*a9643ea8Slogwang typedef struct pptpCodes *PptpCode;
289*a9643ea8Slogwang 
290*a9643ea8Slogwang struct pptpCallIds {
291*a9643ea8Slogwang 	u_int16_t	cid1;	/* Call ID field #1 */
292*a9643ea8Slogwang 	u_int16_t	cid2;	/* Call ID field #2 */
293*a9643ea8Slogwang };
294*a9643ea8Slogwang typedef struct pptpCallIds *PptpCallId;
295*a9643ea8Slogwang 
296*a9643ea8Slogwang static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
297*a9643ea8Slogwang 
298*a9643ea8Slogwang static void
AliasHandlePptpOut(struct libalias * la,struct ip * pip,struct alias_link * lnk)299*a9643ea8Slogwang AliasHandlePptpOut(struct libalias *la,
300*a9643ea8Slogwang     struct ip *pip,		/* IP packet to examine/patch */
301*a9643ea8Slogwang     struct alias_link *lnk)
302*a9643ea8Slogwang {				/* The PPTP control link */
303*a9643ea8Slogwang 	struct alias_link *pptp_lnk;
304*a9643ea8Slogwang 	PptpCallId cptr;
305*a9643ea8Slogwang 	PptpCode codes;
306*a9643ea8Slogwang 	u_int16_t ctl_type;	/* control message type */
307*a9643ea8Slogwang 	struct tcphdr *tc;
308*a9643ea8Slogwang 
309*a9643ea8Slogwang 	/* Verify valid PPTP control message */
310*a9643ea8Slogwang 	if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
311*a9643ea8Slogwang 		return;
312*a9643ea8Slogwang 
313*a9643ea8Slogwang 	/* Modify certain PPTP messages */
314*a9643ea8Slogwang 	switch (ctl_type) {
315*a9643ea8Slogwang 	case PPTP_OutCallRequest:
316*a9643ea8Slogwang 	case PPTP_OutCallReply:
317*a9643ea8Slogwang 	case PPTP_InCallRequest:
318*a9643ea8Slogwang 	case PPTP_InCallReply:
319*a9643ea8Slogwang 		/*
320*a9643ea8Slogwang 		 * Establish PPTP link for address and Call ID found in
321*a9643ea8Slogwang 		 * control message.
322*a9643ea8Slogwang 		 */
323*a9643ea8Slogwang 		pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
324*a9643ea8Slogwang 		    GetAliasAddress(lnk), cptr->cid1);
325*a9643ea8Slogwang 		break;
326*a9643ea8Slogwang 	case PPTP_CallClearRequest:
327*a9643ea8Slogwang 	case PPTP_CallDiscNotify:
328*a9643ea8Slogwang 		/*
329*a9643ea8Slogwang 		 * Find PPTP link for address and Call ID found in control
330*a9643ea8Slogwang 		 * message.
331*a9643ea8Slogwang 		 */
332*a9643ea8Slogwang 		pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
333*a9643ea8Slogwang 		    GetDestAddress(lnk),
334*a9643ea8Slogwang 		    cptr->cid1);
335*a9643ea8Slogwang 		break;
336*a9643ea8Slogwang 	default:
337*a9643ea8Slogwang 		return;
338*a9643ea8Slogwang 	}
339*a9643ea8Slogwang 
340*a9643ea8Slogwang 	if (pptp_lnk != NULL) {
341*a9643ea8Slogwang 		int accumulate = cptr->cid1;
342*a9643ea8Slogwang 
343*a9643ea8Slogwang 		/* alias the Call Id */
344*a9643ea8Slogwang 		cptr->cid1 = GetAliasPort(pptp_lnk);
345*a9643ea8Slogwang 
346*a9643ea8Slogwang 		/* Compute TCP checksum for revised packet */
347*a9643ea8Slogwang 		tc = (struct tcphdr *)ip_next(pip);
348*a9643ea8Slogwang 		accumulate -= cptr->cid1;
349*a9643ea8Slogwang 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
350*a9643ea8Slogwang 
351*a9643ea8Slogwang 		switch (ctl_type) {
352*a9643ea8Slogwang 		case PPTP_OutCallReply:
353*a9643ea8Slogwang 		case PPTP_InCallReply:
354*a9643ea8Slogwang 			codes = (PptpCode) (cptr + 1);
355*a9643ea8Slogwang 			if (codes->resCode == 1)	/* Connection
356*a9643ea8Slogwang 							 * established, */
357*a9643ea8Slogwang 				SetDestCallId(pptp_lnk,	/* note the Peer's Call
358*a9643ea8Slogwang 								 * ID. */
359*a9643ea8Slogwang 				    cptr->cid2);
360*a9643ea8Slogwang 			else
361*a9643ea8Slogwang 				SetExpire(pptp_lnk, 0);	/* Connection refused. */
362*a9643ea8Slogwang 			break;
363*a9643ea8Slogwang 		case PPTP_CallDiscNotify:	/* Connection closed. */
364*a9643ea8Slogwang 			SetExpire(pptp_lnk, 0);
365*a9643ea8Slogwang 			break;
366*a9643ea8Slogwang 		}
367*a9643ea8Slogwang 	}
368*a9643ea8Slogwang }
369*a9643ea8Slogwang 
370*a9643ea8Slogwang static void
AliasHandlePptpIn(struct libalias * la,struct ip * pip,struct alias_link * lnk)371*a9643ea8Slogwang AliasHandlePptpIn(struct libalias *la,
372*a9643ea8Slogwang     struct ip *pip,		/* IP packet to examine/patch */
373*a9643ea8Slogwang     struct alias_link *lnk)
374*a9643ea8Slogwang {				/* The PPTP control link */
375*a9643ea8Slogwang 	struct alias_link *pptp_lnk;
376*a9643ea8Slogwang 	PptpCallId cptr;
377*a9643ea8Slogwang 	u_int16_t *pcall_id;
378*a9643ea8Slogwang 	u_int16_t ctl_type;	/* control message type */
379*a9643ea8Slogwang 	struct tcphdr *tc;
380*a9643ea8Slogwang 
381*a9643ea8Slogwang 	/* Verify valid PPTP control message */
382*a9643ea8Slogwang 	if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
383*a9643ea8Slogwang 		return;
384*a9643ea8Slogwang 
385*a9643ea8Slogwang 	/* Modify certain PPTP messages */
386*a9643ea8Slogwang 	switch (ctl_type) {
387*a9643ea8Slogwang 	case PPTP_InCallConn:
388*a9643ea8Slogwang 	case PPTP_WanErrorNotify:
389*a9643ea8Slogwang 	case PPTP_SetLinkInfo:
390*a9643ea8Slogwang 		pcall_id = &cptr->cid1;
391*a9643ea8Slogwang 		break;
392*a9643ea8Slogwang 	case PPTP_OutCallReply:
393*a9643ea8Slogwang 	case PPTP_InCallReply:
394*a9643ea8Slogwang 		pcall_id = &cptr->cid2;
395*a9643ea8Slogwang 		break;
396*a9643ea8Slogwang 	case PPTP_CallDiscNotify:	/* Connection closed. */
397*a9643ea8Slogwang 		pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
398*a9643ea8Slogwang 		    GetAliasAddress(lnk),
399*a9643ea8Slogwang 		    cptr->cid1);
400*a9643ea8Slogwang 		if (pptp_lnk != NULL)
401*a9643ea8Slogwang 			SetExpire(pptp_lnk, 0);
402*a9643ea8Slogwang 		return;
403*a9643ea8Slogwang 	default:
404*a9643ea8Slogwang 		return;
405*a9643ea8Slogwang 	}
406*a9643ea8Slogwang 
407*a9643ea8Slogwang 	/* Find PPTP link for address and Call ID found in PPTP Control Msg */
408*a9643ea8Slogwang 	pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
409*a9643ea8Slogwang 	    GetAliasAddress(lnk),
410*a9643ea8Slogwang 	    *pcall_id);
411*a9643ea8Slogwang 
412*a9643ea8Slogwang 	if (pptp_lnk != NULL) {
413*a9643ea8Slogwang 		int accumulate = *pcall_id;
414*a9643ea8Slogwang 
415*a9643ea8Slogwang 		/* De-alias the Peer's Call Id. */
416*a9643ea8Slogwang 		*pcall_id = GetOriginalPort(pptp_lnk);
417*a9643ea8Slogwang 
418*a9643ea8Slogwang 		/* Compute TCP checksum for modified packet */
419*a9643ea8Slogwang 		tc = (struct tcphdr *)ip_next(pip);
420*a9643ea8Slogwang 		accumulate -= *pcall_id;
421*a9643ea8Slogwang 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
422*a9643ea8Slogwang 
423*a9643ea8Slogwang 		if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) {
424*a9643ea8Slogwang 			PptpCode codes = (PptpCode) (cptr + 1);
425*a9643ea8Slogwang 
426*a9643ea8Slogwang 			if (codes->resCode == 1)	/* Connection
427*a9643ea8Slogwang 							 * established, */
428*a9643ea8Slogwang 				SetDestCallId(pptp_lnk,	/* note the Call ID. */
429*a9643ea8Slogwang 				    cptr->cid1);
430*a9643ea8Slogwang 			else
431*a9643ea8Slogwang 				SetExpire(pptp_lnk, 0);	/* Connection refused. */
432*a9643ea8Slogwang 		}
433*a9643ea8Slogwang 	}
434*a9643ea8Slogwang }
435*a9643ea8Slogwang 
436*a9643ea8Slogwang static		PptpCallId
AliasVerifyPptp(struct ip * pip,u_int16_t * ptype)437*a9643ea8Slogwang AliasVerifyPptp(struct ip *pip, u_int16_t * ptype)
438*a9643ea8Slogwang {				/* IP packet to examine/patch */
439*a9643ea8Slogwang 	int hlen, tlen, dlen;
440*a9643ea8Slogwang 	PptpMsgHead hptr;
441*a9643ea8Slogwang 	struct tcphdr *tc;
442*a9643ea8Slogwang 
443*a9643ea8Slogwang 	/* Calculate some lengths */
444*a9643ea8Slogwang 	tc = (struct tcphdr *)ip_next(pip);
445*a9643ea8Slogwang 	hlen = (pip->ip_hl + tc->th_off) << 2;
446*a9643ea8Slogwang 	tlen = ntohs(pip->ip_len);
447*a9643ea8Slogwang 	dlen = tlen - hlen;
448*a9643ea8Slogwang 
449*a9643ea8Slogwang 	/* Verify data length */
450*a9643ea8Slogwang 	if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
451*a9643ea8Slogwang 		return (NULL);
452*a9643ea8Slogwang 
453*a9643ea8Slogwang 	/* Move up to PPTP message header */
454*a9643ea8Slogwang 	hptr = (PptpMsgHead) tcp_next(tc);
455*a9643ea8Slogwang 
456*a9643ea8Slogwang 	/* Return the control message type */
457*a9643ea8Slogwang 	*ptype = ntohs(hptr->type);
458*a9643ea8Slogwang 
459*a9643ea8Slogwang 	/* Verify PPTP Control Message */
460*a9643ea8Slogwang 	if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
461*a9643ea8Slogwang 	    (ntohl(hptr->magic) != PPTP_MAGIC))
462*a9643ea8Slogwang 		return (NULL);
463*a9643ea8Slogwang 
464*a9643ea8Slogwang 	/* Verify data length. */
465*a9643ea8Slogwang 	if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
466*a9643ea8Slogwang 	    (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
467*a9643ea8Slogwang 		sizeof(struct pptpCodes))))
468*a9643ea8Slogwang 		return (NULL);
469*a9643ea8Slogwang 	else
470*a9643ea8Slogwang 		return (PptpCallId) (hptr + 1);
471*a9643ea8Slogwang }
472*a9643ea8Slogwang 
473*a9643ea8Slogwang static int
AliasHandlePptpGreOut(struct libalias * la,struct ip * pip)474*a9643ea8Slogwang AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
475*a9643ea8Slogwang {
476*a9643ea8Slogwang 	GreHdr *gr;
477*a9643ea8Slogwang 	struct alias_link *lnk;
478*a9643ea8Slogwang 
479*a9643ea8Slogwang 	gr = (GreHdr *) ip_next(pip);
480*a9643ea8Slogwang 
481*a9643ea8Slogwang 	/* Check GRE header bits. */
482*a9643ea8Slogwang 	if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
483*a9643ea8Slogwang 		return (-1);
484*a9643ea8Slogwang 
485*a9643ea8Slogwang 	lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
486*a9643ea8Slogwang 	if (lnk != NULL) {
487*a9643ea8Slogwang 		struct in_addr alias_addr = GetAliasAddress(lnk);
488*a9643ea8Slogwang 
489*a9643ea8Slogwang 		/* Change source IP address. */
490*a9643ea8Slogwang 		DifferentialChecksum(&pip->ip_sum,
491*a9643ea8Slogwang 		    &alias_addr, &pip->ip_src, 2);
492*a9643ea8Slogwang 		pip->ip_src = alias_addr;
493*a9643ea8Slogwang 	}
494*a9643ea8Slogwang 	return (0);
495*a9643ea8Slogwang }
496*a9643ea8Slogwang 
497*a9643ea8Slogwang static int
AliasHandlePptpGreIn(struct libalias * la,struct ip * pip)498*a9643ea8Slogwang AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
499*a9643ea8Slogwang {
500*a9643ea8Slogwang 	GreHdr *gr;
501*a9643ea8Slogwang 	struct alias_link *lnk;
502*a9643ea8Slogwang 
503*a9643ea8Slogwang 	gr = (GreHdr *) ip_next(pip);
504*a9643ea8Slogwang 
505*a9643ea8Slogwang 	/* Check GRE header bits. */
506*a9643ea8Slogwang 	if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
507*a9643ea8Slogwang 		return (-1);
508*a9643ea8Slogwang 
509*a9643ea8Slogwang 	lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
510*a9643ea8Slogwang 	if (lnk != NULL) {
511*a9643ea8Slogwang 		struct in_addr src_addr = GetOriginalAddress(lnk);
512*a9643ea8Slogwang 
513*a9643ea8Slogwang 		/* De-alias the Peer's Call Id. */
514*a9643ea8Slogwang 		gr->gh_call_id = GetOriginalPort(lnk);
515*a9643ea8Slogwang 
516*a9643ea8Slogwang 		/* Restore original IP address. */
517*a9643ea8Slogwang 		DifferentialChecksum(&pip->ip_sum,
518*a9643ea8Slogwang 		    &src_addr, &pip->ip_dst, 2);
519*a9643ea8Slogwang 		pip->ip_dst = src_addr;
520*a9643ea8Slogwang 	}
521*a9643ea8Slogwang 	return (0);
522*a9643ea8Slogwang }
523