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