xref: /freebsd/sys/netinet/libalias/alias_pptp.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
155a39fc5SRuslan Ermilov /*
255a39fc5SRuslan Ermilov  * alias_pptp.c
355a39fc5SRuslan Ermilov  *
455a39fc5SRuslan Ermilov  * Copyright (c) 2000 Whistle Communications, Inc.
555a39fc5SRuslan Ermilov  * All rights reserved.
655a39fc5SRuslan Ermilov  *
755a39fc5SRuslan Ermilov  * Subject to the following obligations and disclaimer of warranty, use and
855a39fc5SRuslan Ermilov  * redistribution of this software, in source or object code forms, with or
955a39fc5SRuslan Ermilov  * without modifications are expressly permitted by Whistle Communications;
1055a39fc5SRuslan Ermilov  * provided, however, that:
1155a39fc5SRuslan Ermilov  * 1. Any and all reproductions of the source or object code must include the
1255a39fc5SRuslan Ermilov  *    copyright notice above and the following disclaimer of warranties; and
1355a39fc5SRuslan Ermilov  * 2. No rights are granted, in any manner or form, to use Whistle
1455a39fc5SRuslan Ermilov  *    Communications, Inc. trademarks, including the mark "WHISTLE
1555a39fc5SRuslan Ermilov  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1655a39fc5SRuslan Ermilov  *    such appears in the above copyright notice or in the software.
1755a39fc5SRuslan Ermilov  *
1855a39fc5SRuslan Ermilov  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
1955a39fc5SRuslan Ermilov  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2055a39fc5SRuslan Ermilov  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2155a39fc5SRuslan Ermilov  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2255a39fc5SRuslan Ermilov  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2355a39fc5SRuslan Ermilov  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2455a39fc5SRuslan Ermilov  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2555a39fc5SRuslan Ermilov  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2655a39fc5SRuslan Ermilov  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2755a39fc5SRuslan Ermilov  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2855a39fc5SRuslan Ermilov  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
2955a39fc5SRuslan Ermilov  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3055a39fc5SRuslan Ermilov  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3155a39fc5SRuslan Ermilov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3255a39fc5SRuslan Ermilov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3355a39fc5SRuslan Ermilov  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3455a39fc5SRuslan Ermilov  * OF SUCH DAMAGE.
3555a39fc5SRuslan Ermilov  *
3655a39fc5SRuslan Ermilov  * Author: Erik Salander <erik@whistle.com>
3755a39fc5SRuslan Ermilov  */
3855a39fc5SRuslan Ermilov 
39e2505aa6SMatthew Dillon #include <sys/cdefs.h>
40be4f3cd0SPaolo Pisati /* Includes */
41be4f3cd0SPaolo Pisati #ifdef _KERNEL
42be4f3cd0SPaolo Pisati #include <sys/param.h>
43be4f3cd0SPaolo Pisati #include <sys/limits.h>
44be4f3cd0SPaolo Pisati #include <sys/kernel.h>
45be4f3cd0SPaolo Pisati #include <sys/module.h>
46be4f3cd0SPaolo Pisati #else
47be4f3cd0SPaolo Pisati #include <errno.h>
48be4f3cd0SPaolo Pisati #include <limits.h>
49be4f3cd0SPaolo Pisati #include <sys/types.h>
50be4f3cd0SPaolo Pisati #include <stdio.h>
51be4f3cd0SPaolo Pisati #endif
52be4f3cd0SPaolo Pisati 
53be4f3cd0SPaolo Pisati #include <netinet/tcp.h>
54be4f3cd0SPaolo Pisati 
55be4f3cd0SPaolo Pisati #ifdef _KERNEL
56be4f3cd0SPaolo Pisati #include <netinet/libalias/alias.h>
57be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_local.h>
58be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
59be4f3cd0SPaolo Pisati #else
60be4f3cd0SPaolo Pisati #include "alias.h"
61be4f3cd0SPaolo Pisati #include "alias_local.h"
62be4f3cd0SPaolo Pisati #include "alias_mod.h"
63be4f3cd0SPaolo Pisati #endif
64be4f3cd0SPaolo Pisati 
65be4f3cd0SPaolo Pisati #define PPTP_CONTROL_PORT_NUMBER 1723
66be4f3cd0SPaolo Pisati 
67be4f3cd0SPaolo Pisati static void
68be4f3cd0SPaolo Pisati AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *);
69be4f3cd0SPaolo Pisati 
70be4f3cd0SPaolo Pisati static void
71be4f3cd0SPaolo Pisati AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *);
72be4f3cd0SPaolo Pisati 
73be4f3cd0SPaolo Pisati static int
74be4f3cd0SPaolo Pisati AliasHandlePptpGreOut(struct libalias *, struct ip *);
75be4f3cd0SPaolo Pisati 
76be4f3cd0SPaolo Pisati static int
77be4f3cd0SPaolo Pisati AliasHandlePptpGreIn(struct libalias *, struct ip *);
78be4f3cd0SPaolo Pisati 
79be4f3cd0SPaolo Pisati static int
fingerprint(struct libalias * la,struct alias_data * ah)8043197d29SPaolo Pisati fingerprint(struct libalias *la, struct alias_data *ah)
81be4f3cd0SPaolo Pisati {
82be4f3cd0SPaolo Pisati 	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
83be4f3cd0SPaolo Pisati 		return (-1);
84be4f3cd0SPaolo Pisati 	if (ntohs(*ah->dport) == PPTP_CONTROL_PORT_NUMBER
85be4f3cd0SPaolo Pisati 	    || ntohs(*ah->sport) == PPTP_CONTROL_PORT_NUMBER)
86be4f3cd0SPaolo Pisati 		return (0);
87be4f3cd0SPaolo Pisati 	return (-1);
88be4f3cd0SPaolo Pisati }
89be4f3cd0SPaolo Pisati 
90be4f3cd0SPaolo Pisati static int
fingerprintgre(struct libalias * la,struct alias_data * ah)9143197d29SPaolo Pisati fingerprintgre(struct libalias *la, struct alias_data *ah)
92be4f3cd0SPaolo Pisati {
93be4f3cd0SPaolo Pisati 	return (0);
94be4f3cd0SPaolo Pisati }
95be4f3cd0SPaolo Pisati 
96be4f3cd0SPaolo Pisati static int
protohandlerin(struct libalias * la,struct ip * pip,struct alias_data * ah)97be4f3cd0SPaolo Pisati protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
98be4f3cd0SPaolo Pisati {
99be4f3cd0SPaolo Pisati 	AliasHandlePptpIn(la, pip, ah->lnk);
100be4f3cd0SPaolo Pisati 	return (0);
101be4f3cd0SPaolo Pisati }
102be4f3cd0SPaolo Pisati 
103be4f3cd0SPaolo Pisati static int
protohandlerout(struct libalias * la,struct ip * pip,struct alias_data * ah)104be4f3cd0SPaolo Pisati protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
105be4f3cd0SPaolo Pisati {
106be4f3cd0SPaolo Pisati 	AliasHandlePptpOut(la, pip, ah->lnk);
107be4f3cd0SPaolo Pisati 	return (0);
108be4f3cd0SPaolo Pisati }
109be4f3cd0SPaolo Pisati 
110be4f3cd0SPaolo Pisati static int
protohandlergrein(struct libalias * la,struct ip * pip,struct alias_data * ah)111be4f3cd0SPaolo Pisati protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
112be4f3cd0SPaolo Pisati {
113be4f3cd0SPaolo Pisati 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
114be4f3cd0SPaolo Pisati 	    AliasHandlePptpGreIn(la, pip) == 0)
115be4f3cd0SPaolo Pisati 		return (0);
116be4f3cd0SPaolo Pisati 	return (-1);
117be4f3cd0SPaolo Pisati }
118be4f3cd0SPaolo Pisati 
119be4f3cd0SPaolo Pisati static int
protohandlergreout(struct libalias * la,struct ip * pip,struct alias_data * ah)120be4f3cd0SPaolo Pisati protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
121be4f3cd0SPaolo Pisati {
122be4f3cd0SPaolo Pisati 	if (AliasHandlePptpGreOut(la, pip) == 0)
123be4f3cd0SPaolo Pisati 		return (0);
124be4f3cd0SPaolo Pisati 	return (-1);
125be4f3cd0SPaolo Pisati }
126be4f3cd0SPaolo Pisati 
127be4f3cd0SPaolo Pisati /* Kernel module definition. */
128be4f3cd0SPaolo Pisati struct proto_handler handlers[] = {
129be4f3cd0SPaolo Pisati 	{
130be4f3cd0SPaolo Pisati 	  .pri = 200,
131be4f3cd0SPaolo Pisati 	  .dir = IN,
132be4f3cd0SPaolo Pisati 	  .proto = TCP,
133be4f3cd0SPaolo Pisati 	  .fingerprint = &fingerprint,
134be4f3cd0SPaolo Pisati 	  .protohandler = &protohandlerin
135be4f3cd0SPaolo Pisati 	},
136be4f3cd0SPaolo Pisati 	{
137be4f3cd0SPaolo Pisati 	  .pri = 210,
138be4f3cd0SPaolo Pisati 	  .dir = OUT,
139be4f3cd0SPaolo Pisati 	  .proto = TCP,
140be4f3cd0SPaolo Pisati 	  .fingerprint = &fingerprint,
141be4f3cd0SPaolo Pisati 	  .protohandler = &protohandlerout
142be4f3cd0SPaolo Pisati 	},
143be4f3cd0SPaolo Pisati /*
144be4f3cd0SPaolo Pisati  * WATCH OUT!!! these 2 handlers NEED a priority of INT_MAX (highest possible)
145be4f3cd0SPaolo Pisati  * cause they will ALWAYS process packets, so they must be the last one
146be4f3cd0SPaolo Pisati  * in chain: look fingerprintgre() above.
147be4f3cd0SPaolo Pisati  */
148be4f3cd0SPaolo Pisati 	{
149be4f3cd0SPaolo Pisati 	  .pri = INT_MAX,
150be4f3cd0SPaolo Pisati 	  .dir = IN,
151be4f3cd0SPaolo Pisati 	  .proto = IP,
152be4f3cd0SPaolo Pisati 	  .fingerprint = &fingerprintgre,
153be4f3cd0SPaolo Pisati 	  .protohandler = &protohandlergrein
154be4f3cd0SPaolo Pisati 	},
155be4f3cd0SPaolo Pisati 	{
156be4f3cd0SPaolo Pisati 	  .pri = INT_MAX,
157be4f3cd0SPaolo Pisati 	  .dir = OUT,
158be4f3cd0SPaolo Pisati 	  .proto = IP,
159be4f3cd0SPaolo Pisati 	  .fingerprint = &fingerprintgre,
160be4f3cd0SPaolo Pisati 	  .protohandler = &protohandlergreout
161be4f3cd0SPaolo Pisati 	},
162be4f3cd0SPaolo Pisati 	{ EOH }
163be4f3cd0SPaolo Pisati };
164be4f3cd0SPaolo Pisati static int
mod_handler(module_t mod,int type,void * data)165be4f3cd0SPaolo Pisati mod_handler(module_t mod, int type, void *data)
166be4f3cd0SPaolo Pisati {
167be4f3cd0SPaolo Pisati 	int error;
168be4f3cd0SPaolo Pisati 
169be4f3cd0SPaolo Pisati 	switch (type) {
170be4f3cd0SPaolo Pisati 	case MOD_LOAD:
171be4f3cd0SPaolo Pisati 		error = 0;
172be4f3cd0SPaolo Pisati 		LibAliasAttachHandlers(handlers);
173be4f3cd0SPaolo Pisati 		break;
174be4f3cd0SPaolo Pisati 	case MOD_UNLOAD:
175be4f3cd0SPaolo Pisati 		error = 0;
176be4f3cd0SPaolo Pisati 		LibAliasDetachHandlers(handlers);
177be4f3cd0SPaolo Pisati 		break;
178be4f3cd0SPaolo Pisati 	default:
179be4f3cd0SPaolo Pisati 		error = EINVAL;
180be4f3cd0SPaolo Pisati 	}
181be4f3cd0SPaolo Pisati 	return (error);
182be4f3cd0SPaolo Pisati }
183be4f3cd0SPaolo Pisati 
184be4f3cd0SPaolo Pisati #ifdef _KERNEL
185be4f3cd0SPaolo Pisati static
186be4f3cd0SPaolo Pisati #endif
187be4f3cd0SPaolo Pisati moduledata_t alias_mod = {
188be4f3cd0SPaolo Pisati        "alias_pptp", mod_handler, NULL
189be4f3cd0SPaolo Pisati };
190be4f3cd0SPaolo Pisati 
191be4f3cd0SPaolo Pisati #ifdef _KERNEL
192be4f3cd0SPaolo Pisati DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
193be4f3cd0SPaolo Pisati MODULE_VERSION(alias_pptp, 1);
194be4f3cd0SPaolo Pisati MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1);
195be4f3cd0SPaolo Pisati #endif
196be4f3cd0SPaolo Pisati 
19755a39fc5SRuslan Ermilov /*
19855a39fc5SRuslan Ermilov    Alias_pptp.c performs special processing for PPTP sessions under TCP.
19955a39fc5SRuslan Ermilov    Specifically, watch PPTP control messages and alias the Call ID or the
20055a39fc5SRuslan Ermilov    Peer's Call ID in the appropriate messages.  Note, PPTP requires
20155a39fc5SRuslan Ermilov    "de-aliasing" of incoming packets, this is different than any other
20255a39fc5SRuslan Ermilov    TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
20355a39fc5SRuslan Ermilov 
2040eb10a09SRuslan Ermilov    For Call IDs encountered for the first time, a PPTP alias link is created.
2050eb10a09SRuslan Ermilov    The PPTP alias link uses the Call ID in place of the original port number.
20655a39fc5SRuslan Ermilov    An alias Call ID is created.
20755a39fc5SRuslan Ermilov 
20855a39fc5SRuslan Ermilov    For this routine to work, the PPTP control messages must fit entirely
20955a39fc5SRuslan Ermilov    into a single TCP packet.  This is typically the case, but is not
21055a39fc5SRuslan Ermilov    required by the spec.
21155a39fc5SRuslan Ermilov 
21255a39fc5SRuslan Ermilov    Unlike some of the other TCP applications that are aliased (ie. FTP,
21355a39fc5SRuslan Ermilov    IRC and RTSP), the PPTP control messages that need to be aliased are
21455a39fc5SRuslan Ermilov    guaranteed to remain the same length.  The aliased Call ID is a fixed
21555a39fc5SRuslan Ermilov    length field.
21655a39fc5SRuslan Ermilov 
21755a39fc5SRuslan Ermilov    Reference: RFC 2637
21855a39fc5SRuslan Ermilov 
21955a39fc5SRuslan Ermilov    Initial version:  May, 2000 (eds)
22055a39fc5SRuslan Ermilov */
22155a39fc5SRuslan Ermilov 
22255a39fc5SRuslan Ermilov /*
22355a39fc5SRuslan Ermilov  * PPTP definitions
22455a39fc5SRuslan Ermilov  */
22555a39fc5SRuslan Ermilov 
226f0f93429SDag-Erling Smørgrav struct grehdr {				/* Enhanced GRE header. */
22703453c5eSRuslan Ermilov 	u_int16_t	gh_flags;	/* Flags. */
22803453c5eSRuslan Ermilov 	u_int16_t	gh_protocol;	/* Protocol type. */
22903453c5eSRuslan Ermilov 	u_int16_t	gh_length;	/* Payload length. */
23003453c5eSRuslan Ermilov 	u_int16_t	gh_call_id;	/* Call ID. */
23155a39fc5SRuslan Ermilov 	u_int32_t	gh_seq_no;	/* Sequence number (optional). */
232f0f93429SDag-Erling Smørgrav 	u_int32_t	gh_ack_no;	/* Acknowledgment number
233f0f93429SDag-Erling Smørgrav 					 * (optional). */
23455a39fc5SRuslan Ermilov };
23503453c5eSRuslan Ermilov typedef struct grehdr GreHdr;
23655a39fc5SRuslan Ermilov 
23755a39fc5SRuslan Ermilov /* The PPTP protocol ID used in the GRE 'proto' field. */
23855a39fc5SRuslan Ermilov #define PPTP_GRE_PROTO          0x880b
23955a39fc5SRuslan Ermilov 
24055a39fc5SRuslan Ermilov /* Bits that must be set a certain way in all PPTP/GRE packets. */
24155a39fc5SRuslan Ermilov #define PPTP_INIT_VALUE		((0x2001 << 16) | PPTP_GRE_PROTO)
24255a39fc5SRuslan Ermilov #define PPTP_INIT_MASK		0xef7fffff
24355a39fc5SRuslan Ermilov 
24455a39fc5SRuslan Ermilov #define PPTP_MAGIC		0x1a2b3c4d
24555a39fc5SRuslan Ermilov #define PPTP_CTRL_MSG_TYPE	1
24655a39fc5SRuslan Ermilov 
24755a39fc5SRuslan Ermilov enum {
24855a39fc5SRuslan Ermilov 	PPTP_StartCtrlConnRequest = 1,
24955a39fc5SRuslan Ermilov 	PPTP_StartCtrlConnReply = 2,
25055a39fc5SRuslan Ermilov 	PPTP_StopCtrlConnRequest = 3,
25155a39fc5SRuslan Ermilov 	PPTP_StopCtrlConnReply = 4,
25255a39fc5SRuslan Ermilov 	PPTP_EchoRequest = 5,
2530eb10a09SRuslan Ermilov 	PPTP_EchoReply = 6,
25455a39fc5SRuslan Ermilov 	PPTP_OutCallRequest = 7,
25555a39fc5SRuslan Ermilov 	PPTP_OutCallReply = 8,
25655a39fc5SRuslan Ermilov 	PPTP_InCallRequest = 9,
25755a39fc5SRuslan Ermilov 	PPTP_InCallReply = 10,
25855a39fc5SRuslan Ermilov 	PPTP_InCallConn = 11,
25955a39fc5SRuslan Ermilov 	PPTP_CallClearRequest = 12,
26055a39fc5SRuslan Ermilov 	PPTP_CallDiscNotify = 13,
26155a39fc5SRuslan Ermilov 	PPTP_WanErrorNotify = 14,
26203453c5eSRuslan Ermilov 	PPTP_SetLinkInfo = 15
26355a39fc5SRuslan Ermilov };
26455a39fc5SRuslan Ermilov 
26555a39fc5SRuslan Ermilov /* Message structures */
26655a39fc5SRuslan Ermilov struct pptpMsgHead {
26755a39fc5SRuslan Ermilov 	u_int16_t	length;	/* total length */
26855a39fc5SRuslan Ermilov 	u_int16_t	msgType;/* PPTP message type */
26955a39fc5SRuslan Ermilov 	u_int32_t	magic;	/* magic cookie */
27055a39fc5SRuslan Ermilov 	u_int16_t	type;	/* control message type */
27155a39fc5SRuslan Ermilov 	u_int16_t	resv0;	/* reserved */
27255a39fc5SRuslan Ermilov };
27355a39fc5SRuslan Ermilov typedef struct pptpMsgHead *PptpMsgHead;
27455a39fc5SRuslan Ermilov 
27503453c5eSRuslan Ermilov struct pptpCodes {
27603453c5eSRuslan Ermilov 	u_int8_t	resCode;/* Result Code */
27703453c5eSRuslan Ermilov 	u_int8_t	errCode;/* Error Code */
27803453c5eSRuslan Ermilov };
27903453c5eSRuslan Ermilov typedef struct pptpCodes *PptpCode;
28003453c5eSRuslan Ermilov 
28155a39fc5SRuslan Ermilov struct pptpCallIds {
28255a39fc5SRuslan Ermilov 	u_int16_t	cid1;	/* Call ID field #1 */
28355a39fc5SRuslan Ermilov 	u_int16_t	cid2;	/* Call ID field #2 */
28455a39fc5SRuslan Ermilov };
28555a39fc5SRuslan Ermilov typedef struct pptpCallIds *PptpCallId;
28655a39fc5SRuslan Ermilov 
28755a39fc5SRuslan Ermilov static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
28855a39fc5SRuslan Ermilov 
289be4f3cd0SPaolo Pisati static void
AliasHandlePptpOut(struct libalias * la,struct ip * pip,struct alias_link * lnk)2905e289f9eSPoul-Henning Kamp AliasHandlePptpOut(struct libalias *la,
2915e289f9eSPoul-Henning Kamp     struct ip *pip,		/* IP packet to examine/patch */
292*effc8e57SLutz Donnerhacke     struct alias_link *lnk)	/* The PPTP control link */
293*effc8e57SLutz Donnerhacke {
294ed01a582SDag-Erling Smørgrav 	struct alias_link *pptp_lnk;
29555a39fc5SRuslan Ermilov 	PptpCallId cptr;
29603453c5eSRuslan Ermilov 	PptpCode codes;
29755a39fc5SRuslan Ermilov 	u_int16_t ctl_type;	/* control message type */
29855a39fc5SRuslan Ermilov 	struct tcphdr *tc;
29955a39fc5SRuslan Ermilov 
30055a39fc5SRuslan Ermilov 	/* Verify valid PPTP control message */
30155a39fc5SRuslan Ermilov 	if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
30255a39fc5SRuslan Ermilov 		return;
30355a39fc5SRuslan Ermilov 
30455a39fc5SRuslan Ermilov 	/* Modify certain PPTP messages */
3050eb10a09SRuslan Ermilov 	switch (ctl_type) {
3060eb10a09SRuslan Ermilov 	case PPTP_OutCallRequest:
3070eb10a09SRuslan Ermilov 	case PPTP_OutCallReply:
3080eb10a09SRuslan Ermilov 	case PPTP_InCallRequest:
3090eb10a09SRuslan Ermilov 	case PPTP_InCallReply:
310f0f93429SDag-Erling Smørgrav 		/*
311f0f93429SDag-Erling Smørgrav 		 * Establish PPTP link for address and Call ID found in
312f0f93429SDag-Erling Smørgrav 		 * control message.
313f0f93429SDag-Erling Smørgrav 		 */
314ed01a582SDag-Erling Smørgrav 		pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
315ed01a582SDag-Erling Smørgrav 		    GetAliasAddress(lnk), cptr->cid1);
31603453c5eSRuslan Ermilov 		break;
3170eb10a09SRuslan Ermilov 	case PPTP_CallClearRequest:
3180eb10a09SRuslan Ermilov 	case PPTP_CallDiscNotify:
319f0f93429SDag-Erling Smørgrav 		/*
320f0f93429SDag-Erling Smørgrav 		 * Find PPTP link for address and Call ID found in control
321f0f93429SDag-Erling Smørgrav 		 * message.
322f0f93429SDag-Erling Smørgrav 		 */
323ed01a582SDag-Erling Smørgrav 		pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
324*effc8e57SLutz Donnerhacke 		    GetDestAddress(lnk), cptr->cid1);
32503453c5eSRuslan Ermilov 		break;
32603453c5eSRuslan Ermilov 	default:
32703453c5eSRuslan Ermilov 		return;
32803453c5eSRuslan Ermilov 	}
32955a39fc5SRuslan Ermilov 
330ed01a582SDag-Erling Smørgrav 	if (pptp_lnk != NULL) {
331934a4fb3SRuslan Ermilov 		int accumulate = cptr->cid1;
332934a4fb3SRuslan Ermilov 
33355a39fc5SRuslan Ermilov 		/* alias the Call Id */
334ed01a582SDag-Erling Smørgrav 		cptr->cid1 = GetAliasPort(pptp_lnk);
33555a39fc5SRuslan Ermilov 
33655a39fc5SRuslan Ermilov 		/* Compute TCP checksum for revised packet */
3379fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
338934a4fb3SRuslan Ermilov 		accumulate -= cptr->cid1;
339934a4fb3SRuslan Ermilov 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
34003453c5eSRuslan Ermilov 
34103453c5eSRuslan Ermilov 		switch (ctl_type) {
34203453c5eSRuslan Ermilov 		case PPTP_OutCallReply:
34303453c5eSRuslan Ermilov 		case PPTP_InCallReply:
34403453c5eSRuslan Ermilov 			codes = (PptpCode)(cptr + 1);
345*effc8e57SLutz Donnerhacke 			if (codes->resCode == 1)
346*effc8e57SLutz Donnerhacke 				/* Connection established,
347*effc8e57SLutz Donnerhacke 				 * note the Peer's Call ID. */
348*effc8e57SLutz Donnerhacke 				SetDestCallId(pptp_lnk, cptr->cid2);
34903453c5eSRuslan Ermilov 			else
350*effc8e57SLutz Donnerhacke 				/* Connection refused. */
351*effc8e57SLutz Donnerhacke 				SetExpire(pptp_lnk, 0);
3520eb10a09SRuslan Ermilov 			break;
353*effc8e57SLutz Donnerhacke 		case PPTP_CallDiscNotify:
354*effc8e57SLutz Donnerhacke 			/* Connection closed. */
355ed01a582SDag-Erling Smørgrav 			SetExpire(pptp_lnk, 0);
35603453c5eSRuslan Ermilov 			break;
35703453c5eSRuslan Ermilov 		}
35855a39fc5SRuslan Ermilov 	}
35955a39fc5SRuslan Ermilov }
36055a39fc5SRuslan Ermilov 
361be4f3cd0SPaolo Pisati static void
AliasHandlePptpIn(struct libalias * la,struct ip * pip,struct alias_link * lnk)3625e289f9eSPoul-Henning Kamp AliasHandlePptpIn(struct libalias *la,
3635e289f9eSPoul-Henning Kamp     struct ip *pip,		/* IP packet to examine/patch */
364*effc8e57SLutz Donnerhacke     struct alias_link *lnk)	/* The PPTP control link */
365*effc8e57SLutz Donnerhacke {
366ed01a582SDag-Erling Smørgrav 	struct alias_link *pptp_lnk;
36755a39fc5SRuslan Ermilov 	PptpCallId cptr;
36855a39fc5SRuslan Ermilov 	u_int16_t *pcall_id;
36955a39fc5SRuslan Ermilov 	u_int16_t ctl_type;	/* control message type */
37055a39fc5SRuslan Ermilov 	struct tcphdr *tc;
37155a39fc5SRuslan Ermilov 
37255a39fc5SRuslan Ermilov 	/* Verify valid PPTP control message */
37355a39fc5SRuslan Ermilov 	if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
37455a39fc5SRuslan Ermilov 		return;
37555a39fc5SRuslan Ermilov 
37655a39fc5SRuslan Ermilov 	/* Modify certain PPTP messages */
377f0f93429SDag-Erling Smørgrav 	switch (ctl_type) {
37855a39fc5SRuslan Ermilov 	case PPTP_InCallConn:
37955a39fc5SRuslan Ermilov 	case PPTP_WanErrorNotify:
38055a39fc5SRuslan Ermilov 	case PPTP_SetLinkInfo:
38155a39fc5SRuslan Ermilov 		pcall_id = &cptr->cid1;
38255a39fc5SRuslan Ermilov 		break;
38355a39fc5SRuslan Ermilov 	case PPTP_OutCallReply:
38455a39fc5SRuslan Ermilov 	case PPTP_InCallReply:
38555a39fc5SRuslan Ermilov 		pcall_id = &cptr->cid2;
38655a39fc5SRuslan Ermilov 		break;
387*effc8e57SLutz Donnerhacke 	case PPTP_CallDiscNotify:
388*effc8e57SLutz Donnerhacke 		/* Connection closed. */
389ed01a582SDag-Erling Smørgrav 		pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
390*effc8e57SLutz Donnerhacke 		    GetAliasAddress(lnk), cptr->cid1);
391ed01a582SDag-Erling Smørgrav 		if (pptp_lnk != NULL)
392ed01a582SDag-Erling Smørgrav 			SetExpire(pptp_lnk, 0);
39303453c5eSRuslan Ermilov 		return;
39455a39fc5SRuslan Ermilov 	default:
39555a39fc5SRuslan Ermilov 		return;
39655a39fc5SRuslan Ermilov 	}
39755a39fc5SRuslan Ermilov 
3980eb10a09SRuslan Ermilov 	/* Find PPTP link for address and Call ID found in PPTP Control Msg */
399ed01a582SDag-Erling Smørgrav 	pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
400*effc8e57SLutz Donnerhacke 	    GetAliasAddress(lnk), *pcall_id);
40155a39fc5SRuslan Ermilov 
402ed01a582SDag-Erling Smørgrav 	if (pptp_lnk != NULL) {
403934a4fb3SRuslan Ermilov 		int accumulate = *pcall_id;
404934a4fb3SRuslan Ermilov 
40503453c5eSRuslan Ermilov 		/* De-alias the Peer's Call Id. */
406ed01a582SDag-Erling Smørgrav 		*pcall_id = GetOriginalPort(pptp_lnk);
40755a39fc5SRuslan Ermilov 
40855a39fc5SRuslan Ermilov 		/* Compute TCP checksum for modified packet */
4099fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
410934a4fb3SRuslan Ermilov 		accumulate -= *pcall_id;
411934a4fb3SRuslan Ermilov 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
41203453c5eSRuslan Ermilov 
413*effc8e57SLutz Donnerhacke 		if (ctl_type == PPTP_OutCallReply ||
414*effc8e57SLutz Donnerhacke 		    ctl_type == PPTP_InCallReply) {
41503453c5eSRuslan Ermilov 			PptpCode codes = (PptpCode)(cptr + 1);
41603453c5eSRuslan Ermilov 
417*effc8e57SLutz Donnerhacke 			if (codes->resCode == 1)
418*effc8e57SLutz Donnerhacke 				/* Connection established,
419*effc8e57SLutz Donnerhacke 				 * note the Call ID. */
420*effc8e57SLutz Donnerhacke 				SetDestCallId(pptp_lnk, cptr->cid1);
42103453c5eSRuslan Ermilov 			else
422*effc8e57SLutz Donnerhacke 				/* Connection refused. */
423*effc8e57SLutz Donnerhacke 				SetExpire(pptp_lnk, 0);
42403453c5eSRuslan Ermilov 		}
42555a39fc5SRuslan Ermilov 	}
42655a39fc5SRuslan Ermilov }
42755a39fc5SRuslan Ermilov 
42803453c5eSRuslan Ermilov static PptpCallId
AliasVerifyPptp(struct ip * pip,u_int16_t * ptype)429*effc8e57SLutz Donnerhacke AliasVerifyPptp(struct ip *pip, u_int16_t * ptype) /* IP packet to examine/patch */
430*effc8e57SLutz Donnerhacke {
43155a39fc5SRuslan Ermilov 	int hlen, tlen, dlen;
43255a39fc5SRuslan Ermilov 	PptpMsgHead hptr;
43355a39fc5SRuslan Ermilov 	struct tcphdr *tc;
43455a39fc5SRuslan Ermilov 
43555a39fc5SRuslan Ermilov 	/* Calculate some lengths */
4369fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
43755a39fc5SRuslan Ermilov 	hlen = (pip->ip_hl + tc->th_off) << 2;
43855a39fc5SRuslan Ermilov 	tlen = ntohs(pip->ip_len);
43955a39fc5SRuslan Ermilov 	dlen = tlen - hlen;
44055a39fc5SRuslan Ermilov 
44155a39fc5SRuslan Ermilov 	/* Verify data length */
442ed01a582SDag-Erling Smørgrav 	if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
44355a39fc5SRuslan Ermilov 		return (NULL);
44455a39fc5SRuslan Ermilov 
44555a39fc5SRuslan Ermilov 	/* Move up to PPTP message header */
4465c7e7e80SJoe Marcus Clarke 	hptr = (PptpMsgHead)tcp_next(tc);
44755a39fc5SRuslan Ermilov 
44855a39fc5SRuslan Ermilov 	/* Return the control message type */
44955a39fc5SRuslan Ermilov 	*ptype = ntohs(hptr->type);
45055a39fc5SRuslan Ermilov 
45155a39fc5SRuslan Ermilov 	/* Verify PPTP Control Message */
45255a39fc5SRuslan Ermilov 	if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
45355a39fc5SRuslan Ermilov 	    (ntohl(hptr->magic) != PPTP_MAGIC))
45455a39fc5SRuslan Ermilov 		return (NULL);
45503453c5eSRuslan Ermilov 
45603453c5eSRuslan Ermilov 	/* Verify data length. */
45703453c5eSRuslan Ermilov 	if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
458ed01a582SDag-Erling Smørgrav 	    (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
459ed01a582SDag-Erling Smørgrav 		sizeof(struct pptpCodes))))
46003453c5eSRuslan Ermilov 		return (NULL);
46155a39fc5SRuslan Ermilov 	else
462*effc8e57SLutz Donnerhacke 		return ((PptpCallId)(hptr + 1));
46303453c5eSRuslan Ermilov }
46403453c5eSRuslan Ermilov 
465be4f3cd0SPaolo Pisati static int
AliasHandlePptpGreOut(struct libalias * la,struct ip * pip)4665e289f9eSPoul-Henning Kamp AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
46703453c5eSRuslan Ermilov {
46803453c5eSRuslan Ermilov 	GreHdr *gr;
469ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
47003453c5eSRuslan Ermilov 
4719fa0fd26SDag-Erling Smørgrav 	gr = (GreHdr *)ip_next(pip);
47203453c5eSRuslan Ermilov 
47303453c5eSRuslan Ermilov 	/* Check GRE header bits. */
47403453c5eSRuslan Ermilov 	if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
47503453c5eSRuslan Ermilov 		return (-1);
47603453c5eSRuslan Ermilov 
477ed01a582SDag-Erling Smørgrav 	lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
478ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
479ed01a582SDag-Erling Smørgrav 		struct in_addr alias_addr = GetAliasAddress(lnk);
48003453c5eSRuslan Ermilov 
48103453c5eSRuslan Ermilov 		/* Change source IP address. */
48203453c5eSRuslan Ermilov 		DifferentialChecksum(&pip->ip_sum,
4832871c501SDag-Erling Smørgrav 		    &alias_addr, &pip->ip_src, 2);
48403453c5eSRuslan Ermilov 		pip->ip_src = alias_addr;
48503453c5eSRuslan Ermilov 	}
48603453c5eSRuslan Ermilov 	return (0);
48703453c5eSRuslan Ermilov }
48803453c5eSRuslan Ermilov 
489be4f3cd0SPaolo Pisati static int
AliasHandlePptpGreIn(struct libalias * la,struct ip * pip)4905e289f9eSPoul-Henning Kamp AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
49103453c5eSRuslan Ermilov {
49203453c5eSRuslan Ermilov 	GreHdr *gr;
493ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
49403453c5eSRuslan Ermilov 
4959fa0fd26SDag-Erling Smørgrav 	gr = (GreHdr *)ip_next(pip);
49603453c5eSRuslan Ermilov 
49703453c5eSRuslan Ermilov 	/* Check GRE header bits. */
49803453c5eSRuslan Ermilov 	if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
49903453c5eSRuslan Ermilov 		return (-1);
50003453c5eSRuslan Ermilov 
501ed01a582SDag-Erling Smørgrav 	lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
502ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
503ed01a582SDag-Erling Smørgrav 		struct in_addr src_addr = GetOriginalAddress(lnk);
50403453c5eSRuslan Ermilov 
50503453c5eSRuslan Ermilov 		/* De-alias the Peer's Call Id. */
506ed01a582SDag-Erling Smørgrav 		gr->gh_call_id = GetOriginalPort(lnk);
50703453c5eSRuslan Ermilov 
50803453c5eSRuslan Ermilov 		/* Restore original IP address. */
50903453c5eSRuslan Ermilov 		DifferentialChecksum(&pip->ip_sum,
5102871c501SDag-Erling Smørgrav 		    &src_addr, &pip->ip_dst, 2);
51103453c5eSRuslan Ermilov 		pip->ip_dst = src_addr;
51203453c5eSRuslan Ermilov 	}
51303453c5eSRuslan Ermilov 	return (0);
51455a39fc5SRuslan Ermilov }
515