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