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