alias.c revision 50194
1/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */ 2/* 3 Alias.c provides supervisory control for the functions of the 4 packet aliasing software. It consists of routines to monitor 5 TCP connection state, protocol-specific aliasing routines, 6 fragment handling and the following outside world functional 7 interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn, 8 PacketAliasIn and PacketAliasOut. 9 10 The other C program files are briefly described. The data 11 structure framework which holds information needed to translate 12 packets is encapsulated in alias_db.c. Data is accessed by 13 function calls, so other segments of the program need not know 14 about the underlying data structures. Alias_ftp.c contains 15 special code for modifying the ftp PORT command used to establish 16 data connections, while alias_irc.c do the same for IRC 17 DCC. Alias_util.c contains a few utility routines. 18 19 This software is placed into the public domain with no restrictions 20 on its distribution. 21 22 Version 1.0 August, 1996 (cjm) 23 24 Version 1.1 August 20, 1996 (cjm) 25 PPP host accepts incoming connections for ports 0 to 1023. 26 (Gary Roberts pointed out the need to handle incoming 27 connections.) 28 29 Version 1.2 September 7, 1996 (cjm) 30 Fragment handling error in alias_db.c corrected. 31 (Tom Torrance helped fix this problem.) 32 33 Version 1.4 September 16, 1996 (cjm) 34 - A more generalized method for handling incoming 35 connections, without the 0-1023 restriction, is 36 implemented in alias_db.c 37 - Improved ICMP support in alias.c. Traceroute 38 packet streams can now be correctly aliased. 39 - TCP connection closing logic simplified in 40 alias.c and now allows for additional 1 minute 41 "grace period" after FIN or RST is observed. 42 43 Version 1.5 September 17, 1996 (cjm) 44 Corrected error in handling incoming UDP packets with 0 checksum. 45 (Tom Torrance helped fix this problem.) 46 47 Version 1.6 September 18, 1996 (cjm) 48 Simplified ICMP aliasing scheme. Should now support 49 traceroute from Win95 as well as FreeBSD. 50 51 Version 1.7 January 9, 1997 (cjm) 52 - Out-of-order fragment handling. 53 - IP checksum error fixed for ftp transfers 54 from aliasing host. 55 - Integer return codes added to all 56 aliasing/de-aliasing functions. 57 - Some obsolete comments cleaned up. 58 - Differential checksum computations for 59 IP header (TCP, UDP and ICMP were already 60 differential). 61 62 Version 2.1 May 1997 (cjm) 63 - Added support for outgoing ICMP error 64 messages. 65 - Added two functions PacketAliasIn2() 66 and PacketAliasOut2() for dynamic address 67 control (e.g. round-robin allocation of 68 incoming packets). 69 70 Version 2.2 July 1997 (cjm) 71 - Rationalized API function names to begin 72 with "PacketAlias..." 73 - Eliminated PacketAliasIn2() and 74 PacketAliasOut2() as poorly conceived. 75 76 Version 2.3 Dec 1998 (dillon) 77 - Major bounds checking additions, see FreeBSD/CVS 78 79 See HISTORY file for additional revisions. 80 81*/ 82 83#include <stdio.h> 84#include <unistd.h> 85 86#include <sys/param.h> 87#include <sys/types.h> 88 89#include <netinet/in_systm.h> 90#include <netinet/in.h> 91#include <netinet/ip.h> 92#include <netinet/ip_icmp.h> 93#include <netinet/tcp.h> 94#include <netinet/udp.h> 95 96#ifndef IPPROTO_GRE 97#define IPPROTO_GRE 47 98#define IPPROTO_ESP 50 99#define IPPROTO_AH 51 100#endif 101 102#include "alias_local.h" 103#include "alias.h" 104 105#define NETBIOS_NS_PORT_NUMBER 137 106#define NETBIOS_DGM_PORT_NUMBER 138 107#define FTP_CONTROL_PORT_NUMBER 21 108#define IRC_CONTROL_PORT_NUMBER_1 6667 109#define IRC_CONTROL_PORT_NUMBER_2 6668 110#define CUSEEME_PORT_NUMBER 7648 111 112 113 114 115/* TCP Handling Routines 116 117 TcpMonitorIn() -- These routines monitor TCP connections, and 118 TcpMonitorOut() delete a link when a connection is closed. 119 120These routines look for SYN, ACK and RST flags to determine when TCP 121connections open and close. When a TCP connection closes, the data 122structure containing packet aliasing information is deleted after 123a timeout period. 124*/ 125 126/* Local prototypes */ 127static void TcpMonitorIn(struct ip *, struct alias_link *); 128 129static void TcpMonitorOut(struct ip *, struct alias_link *); 130 131 132static void 133TcpMonitorIn(struct ip *pip, struct alias_link *link) 134{ 135 struct tcphdr *tc; 136 137 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 138 139 switch (GetStateIn(link)) 140 { 141 case ALIAS_TCP_STATE_NOT_CONNECTED: 142 if (tc->th_flags & TH_SYN) 143 SetStateIn(link, ALIAS_TCP_STATE_CONNECTED); 144 break; 145 case ALIAS_TCP_STATE_CONNECTED: 146 if (tc->th_flags & TH_FIN 147 || tc->th_flags & TH_RST) 148 SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); 149 break; 150 } 151} 152 153static void 154TcpMonitorOut(struct ip *pip, struct alias_link *link) 155{ 156 struct tcphdr *tc; 157 158 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 159 160 switch (GetStateOut(link)) 161 { 162 case ALIAS_TCP_STATE_NOT_CONNECTED: 163 if (tc->th_flags & TH_SYN) 164 SetStateOut(link, ALIAS_TCP_STATE_CONNECTED); 165 break; 166 case ALIAS_TCP_STATE_CONNECTED: 167 if (tc->th_flags & TH_FIN 168 || tc->th_flags & TH_RST) 169 SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); 170 break; 171 } 172} 173 174 175 176 177 178/* Protocol Specific Packet Aliasing Routines 179 180 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3() 181 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3() 182 UdpAliasIn(), UdpAliasOut() 183 TcpAliasIn(), TcpAliasOut() 184 185These routines handle protocol specific details of packet aliasing. 186One may observe a certain amount of repetitive arithmetic in these 187functions, the purpose of which is to compute a revised checksum 188without actually summing over the entire data packet, which could be 189unnecessarily time consuming. 190 191The purpose of the packet aliasing routines is to replace the source 192address of the outgoing packet and then correctly put it back for 193any incoming packets. For TCP and UDP, ports are also re-mapped. 194 195For ICMP echo/timestamp requests and replies, the following scheme 196is used: the id number is replaced by an alias for the outgoing 197packet. 198 199ICMP error messages are handled by looking at the IP fragment 200in the data section of the message. 201 202For TCP and UDP protocols, a port number is chosen for an outgoing 203packet, and then incoming packets are identified by IP address and 204port numbers. For TCP packets, there is additional logic in the event 205that sequence and ack numbers have been altered (as is the case for 206FTP data port commands). 207 208The port numbers used by the packet aliasing module are not true 209ports in the Unix sense. No sockets are actually bound to ports. 210They are more correctly thought of as placeholders. 211 212All packets go through the aliasing mechanism, whether they come from 213the gateway machine or other machines on a local area network. 214*/ 215 216 217/* Local prototypes */ 218static int IcmpAliasIn1(struct ip *); 219static int IcmpAliasIn2(struct ip *); 220static int IcmpAliasIn3(struct ip *); 221static int IcmpAliasIn (struct ip *); 222 223static int IcmpAliasOut1(struct ip *); 224static int IcmpAliasOut2(struct ip *); 225static int IcmpAliasOut3(struct ip *); 226static int IcmpAliasOut (struct ip *); 227 228static int UdpAliasOut(struct ip *); 229static int UdpAliasIn (struct ip *); 230 231static int TcpAliasOut(struct ip *, int); 232static int TcpAliasIn (struct ip *); 233 234 235static int 236IcmpAliasIn1(struct ip *pip) 237{ 238/* 239 De-alias incoming echo and timestamp replies 240*/ 241 struct alias_link *link; 242 struct icmp *ic; 243 244 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 245 246/* Get source address from ICMP data field and restore original data */ 247 link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id); 248 if (link != NULL) 249 { 250 u_short original_id; 251 int accumulate; 252 253 original_id = GetOriginalPort(link); 254 255/* Adjust ICMP checksum */ 256 accumulate = ic->icmp_id; 257 accumulate -= original_id; 258 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 259 260/* Put original sequence number back in */ 261 ic->icmp_id = original_id; 262 263/* Put original address back into IP header */ 264 { 265 struct in_addr original_address; 266 267 original_address = GetOriginalAddress(link); 268 DifferentialChecksum(&pip->ip_sum, 269 (u_short *) &original_address, 270 (u_short *) &pip->ip_dst, 271 2); 272 pip->ip_dst = original_address; 273 } 274 275 return(PKT_ALIAS_OK); 276 } 277 return(PKT_ALIAS_IGNORED); 278} 279 280static int 281IcmpAliasIn2(struct ip *pip) 282{ 283/* 284 Alias incoming ICMP error messages containing 285 IP header and first 64 bits of datagram. 286*/ 287 struct ip *ip; 288 struct icmp *ic, *ic2; 289 struct udphdr *ud; 290 struct tcphdr *tc; 291 struct alias_link *link; 292 293 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 294 ip = (struct ip *) ic->icmp_data; 295 296 ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); 297 tc = (struct tcphdr *) ud; 298 ic2 = (struct icmp *) ud; 299 300 if (ip->ip_p == IPPROTO_UDP) 301 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, 302 ud->uh_dport, ud->uh_sport, 303 IPPROTO_UDP); 304 else if (ip->ip_p == IPPROTO_TCP) 305 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, 306 tc->th_dport, tc->th_sport, 307 IPPROTO_TCP); 308 else if (ip->ip_p == IPPROTO_ICMP) { 309 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 310 link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id); 311 else 312 link = NULL; 313 } else 314 link = NULL; 315 316 if (link != NULL) 317 { 318 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) 319 { 320 u_short *sptr; 321 int accumulate; 322 struct in_addr original_address; 323 u_short original_port; 324 325 original_address = GetOriginalAddress(link); 326 original_port = GetOriginalPort(link); 327 328/* Adjust ICMP checksum */ 329 sptr = (u_short *) &(ip->ip_src); 330 accumulate = *sptr++; 331 accumulate += *sptr; 332 sptr = (u_short *) &original_address; 333 accumulate -= *sptr++; 334 accumulate -= *sptr; 335 accumulate += ud->uh_sport; 336 accumulate -= original_port; 337 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 338 339/* Un-alias address in IP header */ 340 DifferentialChecksum(&pip->ip_sum, 341 (u_short *) &original_address, 342 (u_short *) &pip->ip_dst, 343 2); 344 pip->ip_dst = original_address; 345 346/* Un-alias address and port number of original IP packet 347fragment contained in ICMP data section */ 348 ip->ip_src = original_address; 349 ud->uh_sport = original_port; 350 } 351 else if (pip->ip_p == IPPROTO_ICMP) 352 { 353 u_short *sptr; 354 int accumulate; 355 struct in_addr original_address; 356 u_short original_id; 357 358 original_address = GetOriginalAddress(link); 359 original_id = GetOriginalPort(link); 360 361/* Adjust ICMP checksum */ 362 sptr = (u_short *) &(ip->ip_src); 363 accumulate = *sptr++; 364 accumulate += *sptr; 365 sptr = (u_short *) &original_address; 366 accumulate -= *sptr++; 367 accumulate -= *sptr; 368 accumulate += ic2->icmp_id; 369 accumulate -= original_id; 370 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 371 372/* Un-alias address in IP header */ 373 DifferentialChecksum(&pip->ip_sum, 374 (u_short *) &original_address, 375 (u_short *) &pip->ip_dst, 376 2); 377 pip->ip_dst = original_address; 378 379/* Un-alias address of original IP packet and seqence number of 380 embedded icmp datagram */ 381 ip->ip_src = original_address; 382 ic2->icmp_id = original_id; 383 } 384 return(PKT_ALIAS_OK); 385 } 386 return(PKT_ALIAS_IGNORED); 387} 388 389static int 390IcmpAliasIn3(struct ip *pip) 391{ 392 struct in_addr original_address; 393 394 original_address = FindOriginalAddress(pip->ip_dst); 395 DifferentialChecksum(&pip->ip_sum, 396 (u_short *) &original_address, 397 (u_short *) &pip->ip_dst, 398 2); 399 pip->ip_dst = original_address; 400 401 return PKT_ALIAS_OK; 402} 403 404 405static int 406IcmpAliasIn(struct ip *pip) 407{ 408 int iresult; 409 struct icmp *ic; 410 411/* Return if proxy-only mode is enabled */ 412 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) 413 return PKT_ALIAS_OK; 414 415 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 416 417 iresult = PKT_ALIAS_IGNORED; 418 switch (ic->icmp_type) 419 { 420 case ICMP_ECHOREPLY: 421 case ICMP_TSTAMPREPLY: 422 if (ic->icmp_code == 0) 423 { 424 iresult = IcmpAliasIn1(pip); 425 } 426 break; 427 case ICMP_UNREACH: 428 case ICMP_SOURCEQUENCH: 429 case ICMP_TIMXCEED: 430 case ICMP_PARAMPROB: 431 iresult = IcmpAliasIn2(pip); 432 break; 433 case ICMP_ECHO: 434 case ICMP_TSTAMP: 435 iresult = IcmpAliasIn3(pip); 436 break; 437 } 438 return(iresult); 439} 440 441 442static int 443IcmpAliasOut1(struct ip *pip) 444{ 445/* 446 Alias ICMP echo and timestamp packets 447*/ 448 struct alias_link *link; 449 struct icmp *ic; 450 451 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 452 453/* Save overwritten data for when echo packet returns */ 454 link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id); 455 if (link != NULL) 456 { 457 u_short alias_id; 458 int accumulate; 459 460 alias_id = GetAliasPort(link); 461 462/* Since data field is being modified, adjust ICMP checksum */ 463 accumulate = ic->icmp_id; 464 accumulate -= alias_id; 465 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 466 467/* Alias sequence number */ 468 ic->icmp_id = alias_id; 469 470/* Change source address */ 471 { 472 struct in_addr alias_address; 473 474 alias_address = GetAliasAddress(link); 475 DifferentialChecksum(&pip->ip_sum, 476 (u_short *) &alias_address, 477 (u_short *) &pip->ip_src, 478 2); 479 pip->ip_src = alias_address; 480 } 481 482 return(PKT_ALIAS_OK); 483 } 484 return(PKT_ALIAS_IGNORED); 485} 486 487 488static int 489IcmpAliasOut2(struct ip *pip) 490{ 491/* 492 Alias outgoing ICMP error messages containing 493 IP header and first 64 bits of datagram. 494*/ 495 struct in_addr alias_addr; 496 struct ip *ip; 497 struct icmp *ic; 498 499 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 500 ip = (struct ip *) ic->icmp_data; 501 502 alias_addr = FindAliasAddress(ip->ip_src); 503 504/* Alias destination address in IP fragment */ 505 DifferentialChecksum(&ic->icmp_cksum, 506 (u_short *) &alias_addr, 507 (u_short *) &ip->ip_dst, 508 2); 509 ip->ip_dst = alias_addr; 510 511/* alias source address in IP header */ 512 DifferentialChecksum(&pip->ip_sum, 513 (u_short *) &alias_addr, 514 (u_short *) &pip->ip_src, 515 2); 516 pip->ip_src = alias_addr; 517 518 return PKT_ALIAS_OK; 519} 520 521 522static int 523IcmpAliasOut3(struct ip *pip) 524{ 525/* 526 Handle outgoing echo and timestamp replies. The 527 only thing which is done in this case is to alias 528 the source IP address of the packet. 529*/ 530 struct in_addr alias_addr; 531 532 alias_addr = FindAliasAddress(pip->ip_src); 533 DifferentialChecksum(&pip->ip_sum, 534 (u_short *) &alias_addr, 535 (u_short *) &pip->ip_src, 536 2); 537 pip->ip_src = alias_addr; 538 539 return PKT_ALIAS_OK; 540} 541 542 543static int 544IcmpAliasOut(struct ip *pip) 545{ 546 int iresult; 547 struct icmp *ic; 548 549/* Return if proxy-only mode is enabled */ 550 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) 551 return PKT_ALIAS_OK; 552 553 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 554 555 iresult = PKT_ALIAS_IGNORED; 556 switch (ic->icmp_type) 557 { 558 case ICMP_ECHO: 559 case ICMP_TSTAMP: 560 if (ic->icmp_code == 0) 561 { 562 iresult = IcmpAliasOut1(pip); 563 } 564 break; 565 case ICMP_UNREACH: 566 case ICMP_SOURCEQUENCH: 567 case ICMP_TIMXCEED: 568 case ICMP_PARAMPROB: 569 iresult = IcmpAliasOut2(pip); 570 break; 571 case ICMP_ECHOREPLY: 572 case ICMP_TSTAMPREPLY: 573 iresult = IcmpAliasOut3(pip); 574 } 575 return(iresult); 576} 577 578 579 580static int 581PptpAliasIn(struct ip *pip) 582{ 583/* 584 Handle incoming PPTP packets. The 585 only thing which is done in this case is to alias 586 the dest IP address of the packet to our inside 587 machine. 588*/ 589 struct in_addr alias_addr; 590 591 if (!GetPptpAlias (&alias_addr)) 592 return PKT_ALIAS_IGNORED; 593 594 if (pip->ip_src.s_addr != alias_addr.s_addr) { 595 596 DifferentialChecksum(&pip->ip_sum, 597 (u_short *) &alias_addr, 598 (u_short *) &pip->ip_dst, 599 2); 600 pip->ip_dst = alias_addr; 601 } 602 603 return PKT_ALIAS_OK; 604} 605 606 607static int 608PptpAliasOut(struct ip *pip) 609{ 610/* 611 Handle outgoing PPTP packets. The 612 only thing which is done in this case is to alias 613 the source IP address of the packet. 614*/ 615 struct in_addr alias_addr; 616 617 if (!GetPptpAlias (&alias_addr)) 618 return PKT_ALIAS_IGNORED; 619 620 if (pip->ip_src.s_addr == alias_addr.s_addr) { 621 622 alias_addr = FindAliasAddress(pip->ip_src); 623 DifferentialChecksum(&pip->ip_sum, 624 (u_short *) &alias_addr, 625 (u_short *) &pip->ip_src, 626 2); 627 pip->ip_src = alias_addr; 628 } 629 630 return PKT_ALIAS_OK; 631} 632 633 634 635static int 636UdpAliasIn(struct ip *pip) 637{ 638 struct udphdr *ud; 639 struct alias_link *link; 640 641/* Return if proxy-only mode is enabled */ 642 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) 643 return PKT_ALIAS_OK; 644 645 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 646 647 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, 648 ud->uh_sport, ud->uh_dport, 649 IPPROTO_UDP); 650 if (link != NULL) 651 { 652 struct in_addr alias_address; 653 struct in_addr original_address; 654 u_short alias_port; 655 int accumulate; 656 u_short *sptr; 657 int r = 0; 658 659 alias_address = GetAliasAddress(link); 660 original_address = GetOriginalAddress(link); 661 alias_port = ud->uh_dport; 662 ud->uh_dport = GetOriginalPort(link); 663 664/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ 665 if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER 666 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) 667 { 668 r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport); 669 } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER 670 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) 671 { 672 r = AliasHandleUdpNbtNS(pip, link, 673 &alias_address, 674 &alias_port, 675 &original_address, 676 &ud->uh_dport ); 677 } 678 679 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) 680 AliasHandleCUSeeMeIn(pip, original_address); 681 682/* If UDP checksum is not zero, then adjust since destination port */ 683/* is being unaliased and destination port is being altered. */ 684 if (ud->uh_sum != 0) 685 { 686 accumulate = alias_port; 687 accumulate -= ud->uh_dport; 688 sptr = (u_short *) &alias_address; 689 accumulate += *sptr++; 690 accumulate += *sptr; 691 sptr = (u_short *) &original_address; 692 accumulate -= *sptr++; 693 accumulate -= *sptr; 694 ADJUST_CHECKSUM(accumulate, ud->uh_sum) 695 } 696 697/* Restore original IP address */ 698 DifferentialChecksum(&pip->ip_sum, 699 (u_short *) &original_address, 700 (u_short *) &pip->ip_dst, 701 2); 702 pip->ip_dst = original_address; 703 704 /* 705 * If we cannot figure out the packet, ignore it. 706 */ 707 if (r < 0) 708 return(PKT_ALIAS_IGNORED); 709 else 710 return(PKT_ALIAS_OK); 711 } 712 return(PKT_ALIAS_IGNORED); 713} 714 715static int 716UdpAliasOut(struct ip *pip) 717{ 718 struct udphdr *ud; 719 struct alias_link *link; 720 721/* Return if proxy-only mode is enabled */ 722 if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) 723 return PKT_ALIAS_OK; 724 725 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 726 727 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, 728 ud->uh_sport, ud->uh_dport, 729 IPPROTO_UDP); 730 if (link != NULL) 731 { 732 u_short alias_port; 733 struct in_addr alias_address; 734 735 alias_address = GetAliasAddress(link); 736 alias_port = GetAliasPort(link); 737 738 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) 739 AliasHandleCUSeeMeOut(pip, link); 740 741/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ 742 if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER 743 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) 744 { 745 AliasHandleUdpNbt(pip, link, &alias_address, alias_port); 746 } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER 747 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) 748 { 749 AliasHandleUdpNbtNS(pip, link, 750 &pip->ip_src, 751 &ud->uh_sport, 752 &alias_address, 753 &alias_port); 754 } 755 756/* If UDP checksum is not zero, adjust since source port is */ 757/* being aliased and source address is being altered */ 758 if (ud->uh_sum != 0) 759 { 760 int accumulate; 761 u_short *sptr; 762 763 accumulate = ud->uh_sport; 764 accumulate -= alias_port; 765 sptr = (u_short *) &(pip->ip_src); 766 accumulate += *sptr++; 767 accumulate += *sptr; 768 sptr = (u_short *) &alias_address; 769 accumulate -= *sptr++; 770 accumulate -= *sptr; 771 ADJUST_CHECKSUM(accumulate, ud->uh_sum) 772 } 773 774/* Put alias port in UDP header */ 775 ud->uh_sport = alias_port; 776 777/* Change source address */ 778 DifferentialChecksum(&pip->ip_sum, 779 (u_short *) &alias_address, 780 (u_short *) &pip->ip_src, 781 2); 782 pip->ip_src = alias_address; 783 784 return(PKT_ALIAS_OK); 785 } 786 return(PKT_ALIAS_IGNORED); 787} 788 789 790 791static int 792TcpAliasIn(struct ip *pip) 793{ 794 struct tcphdr *tc; 795 struct alias_link *link; 796 797 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 798 799 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, 800 tc->th_sport, tc->th_dport, 801 IPPROTO_TCP); 802 if (link != NULL) 803 { 804 struct in_addr alias_address; 805 struct in_addr original_address; 806 struct in_addr proxy_address; 807 u_short alias_port; 808 u_short proxy_port; 809 int accumulate; 810 u_short *sptr; 811 812 alias_address = GetAliasAddress(link); 813 original_address = GetOriginalAddress(link); 814 proxy_address = GetProxyAddress(link); 815 alias_port = tc->th_dport; 816 tc->th_dport = GetOriginalPort(link); 817 proxy_port = GetProxyPort(link); 818 819/* Adjust TCP checksum since destination port is being unaliased */ 820/* and destination port is being altered. */ 821 accumulate = alias_port; 822 accumulate -= tc->th_dport; 823 sptr = (u_short *) &alias_address; 824 accumulate += *sptr++; 825 accumulate += *sptr; 826 sptr = (u_short *) &original_address; 827 accumulate -= *sptr++; 828 accumulate -= *sptr; 829 830/* If this is a proxy, then modify the tcp source port and 831 checksum accumulation */ 832 if (proxy_port != 0) 833 { 834 accumulate += tc->th_sport; 835 tc->th_sport = proxy_port; 836 accumulate -= tc->th_sport; 837 838 sptr = (u_short *) &pip->ip_src; 839 accumulate += *sptr++; 840 accumulate += *sptr; 841 sptr = (u_short *) &proxy_address; 842 accumulate -= *sptr++; 843 accumulate -= *sptr; 844 } 845 846/* See if ack number needs to be modified */ 847 if (GetAckModified(link) == 1) 848 { 849 int delta; 850 851 delta = GetDeltaAckIn(pip, link); 852 if (delta != 0) 853 { 854 sptr = (u_short *) &tc->th_ack; 855 accumulate += *sptr++; 856 accumulate += *sptr; 857 tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 858 sptr = (u_short *) &tc->th_ack; 859 accumulate -= *sptr++; 860 accumulate -= *sptr; 861 } 862 } 863 864 ADJUST_CHECKSUM(accumulate, tc->th_sum); 865 866/* Restore original IP address */ 867 sptr = (u_short *) &pip->ip_dst; 868 accumulate = *sptr++; 869 accumulate += *sptr; 870 pip->ip_dst = original_address; 871 sptr = (u_short *) &pip->ip_dst; 872 accumulate -= *sptr++; 873 accumulate -= *sptr; 874 875/* If this is a transparent proxy packet, then modify the source 876 address */ 877 if (proxy_address.s_addr != 0) 878 { 879 sptr = (u_short *) &pip->ip_src; 880 accumulate += *sptr++; 881 accumulate += *sptr; 882 pip->ip_src = proxy_address; 883 sptr = (u_short *) &pip->ip_src; 884 accumulate -= *sptr++; 885 accumulate -= *sptr; 886 } 887 888 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 889 890/* Monitor TCP connection state */ 891 TcpMonitorIn(pip, link); 892 893 return(PKT_ALIAS_OK); 894 } 895 return(PKT_ALIAS_IGNORED); 896} 897 898static int 899TcpAliasOut(struct ip *pip, int maxpacketsize) 900{ 901 int proxy_type; 902 u_short dest_port; 903 u_short proxy_server_port; 904 struct in_addr dest_address; 905 struct in_addr proxy_server_address; 906 struct tcphdr *tc; 907 struct alias_link *link; 908 909 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 910 911 proxy_type = ProxyCheck(pip, &proxy_server_address, &proxy_server_port); 912 913 if (proxy_type == 0 && (packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 914 return PKT_ALIAS_OK; 915 916/* If this is a transparent proxy, save original destination, 917 then alter the destination and adust checksums */ 918 dest_port = tc->th_dport; 919 dest_address = pip->ip_dst; 920 if (proxy_type != 0) 921 { 922 int accumulate; 923 u_short *sptr; 924 925 accumulate = tc->th_dport; 926 tc->th_dport = proxy_server_port; 927 accumulate -= tc->th_dport; 928 929 sptr = (u_short *) &(pip->ip_dst); 930 accumulate += *sptr++; 931 accumulate += *sptr; 932 sptr = (u_short *) &proxy_server_address; 933 accumulate -= *sptr++; 934 accumulate -= *sptr; 935 936 ADJUST_CHECKSUM(accumulate, tc->th_sum); 937 938 sptr = (u_short *) &(pip->ip_dst); 939 accumulate = *sptr++; 940 accumulate += *sptr; 941 pip->ip_dst = proxy_server_address; 942 sptr = (u_short *) &(pip->ip_dst); 943 accumulate -= *sptr++; 944 accumulate -= *sptr; 945 946 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 947 } 948 949 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, 950 tc->th_sport, tc->th_dport, 951 IPPROTO_TCP); 952 if (link !=NULL) 953 { 954 u_short alias_port; 955 struct in_addr alias_address; 956 int accumulate; 957 u_short *sptr; 958 959/* Save original destination address, if this is a proxy packet. 960 Also modify packet to include destination encoding. */ 961 if (proxy_type != 0) 962 { 963 SetProxyPort(link, dest_port); 964 SetProxyAddress(link, dest_address); 965 ProxyModify(link, pip, maxpacketsize, proxy_type); 966 } 967 968/* Get alias address and port */ 969 alias_port = GetAliasPort(link); 970 alias_address = GetAliasAddress(link); 971 972/* Monitor tcp connection state */ 973 TcpMonitorOut(pip, link); 974 975/* Special processing for IP encoding protocols */ 976 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER 977 || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER) 978 AliasHandleFtpOut(pip, link, maxpacketsize); 979 if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 980 || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2) 981 AliasHandleIrcOut(pip, link, maxpacketsize); 982 983/* Adjust TCP checksum since source port is being aliased */ 984/* and source address is being altered */ 985 accumulate = tc->th_sport; 986 tc->th_sport = alias_port; 987 accumulate -= tc->th_sport; 988 989 sptr = (u_short *) &(pip->ip_src); 990 accumulate += *sptr++; 991 accumulate += *sptr; 992 sptr = (u_short *) &alias_address; 993 accumulate -= *sptr++; 994 accumulate -= *sptr; 995 996/* Modify sequence number if necessary */ 997 if (GetAckModified(link) == 1) 998 { 999 int delta; 1000 1001 delta = GetDeltaSeqOut(pip, link); 1002 if (delta != 0) 1003 { 1004 sptr = (u_short *) &tc->th_seq; 1005 accumulate += *sptr++; 1006 accumulate += *sptr; 1007 tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 1008 sptr = (u_short *) &tc->th_seq; 1009 accumulate -= *sptr++; 1010 accumulate -= *sptr; 1011 } 1012 } 1013 1014 ADJUST_CHECKSUM(accumulate, tc->th_sum) 1015 1016/* Change source address */ 1017 sptr = (u_short *) &(pip->ip_src); 1018 accumulate = *sptr++; 1019 accumulate += *sptr; 1020 pip->ip_src = alias_address; 1021 sptr = (u_short *) &(pip->ip_src); 1022 accumulate -= *sptr++; 1023 accumulate -= *sptr; 1024 1025 ADJUST_CHECKSUM(accumulate, pip->ip_sum) 1026 1027 return(PKT_ALIAS_OK); 1028 } 1029 return(PKT_ALIAS_IGNORED); 1030} 1031 1032 1033 1034 1035/* Fragment Handling 1036 1037 FragmentIn() 1038 FragmentOut() 1039 1040The packet aliasing module has a limited ability for handling IP 1041fragments. If the ICMP, TCP or UDP header is in the first fragment 1042received, then the id number of the IP packet is saved, and other 1043fragments are identified according to their ID number and IP address 1044they were sent from. Pointers to unresolved fragments can also be 1045saved and recalled when a header fragment is seen. 1046*/ 1047 1048/* Local prototypes */ 1049static int FragmentIn(struct ip *); 1050static int FragmentOut(struct ip *); 1051 1052 1053static int 1054FragmentIn(struct ip *pip) 1055{ 1056 struct alias_link *link; 1057 1058 link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id); 1059 if (link != NULL) 1060 { 1061 struct in_addr original_address; 1062 1063 GetFragmentAddr(link, &original_address); 1064 DifferentialChecksum(&pip->ip_sum, 1065 (u_short *) &original_address, 1066 (u_short *) &pip->ip_dst, 1067 2); 1068 pip->ip_dst = original_address; 1069 1070 return(PKT_ALIAS_OK); 1071 } 1072 return(PKT_ALIAS_UNRESOLVED_FRAGMENT); 1073} 1074 1075 1076static int 1077FragmentOut(struct ip *pip) 1078{ 1079 struct in_addr alias_address; 1080 1081 alias_address = FindAliasAddress(pip->ip_src); 1082 DifferentialChecksum(&pip->ip_sum, 1083 (u_short *) &alias_address, 1084 (u_short *) &pip->ip_src, 1085 2); 1086 pip->ip_src = alias_address; 1087 1088 return(PKT_ALIAS_OK); 1089} 1090 1091 1092 1093 1094 1095 1096/* Outside World Access 1097 1098 PacketAliasSaveFragment() 1099 PacketAliasGetFragment() 1100 PacketAliasFragmentIn() 1101 PacketAliasIn() 1102 PacketAliasOut() 1103 1104(prototypes in alias.h) 1105*/ 1106 1107 1108int 1109PacketAliasSaveFragment(char *ptr) 1110{ 1111 int iresult; 1112 struct alias_link *link; 1113 struct ip *pip; 1114 1115 pip = (struct ip *) ptr; 1116 link = AddFragmentPtrLink(pip->ip_src, pip->ip_id); 1117 iresult = PKT_ALIAS_ERROR; 1118 if (link != NULL) 1119 { 1120 SetFragmentPtr(link, ptr); 1121 iresult = PKT_ALIAS_OK; 1122 } 1123 return(iresult); 1124} 1125 1126 1127char * 1128PacketAliasGetFragment(char *ptr) 1129{ 1130 struct alias_link *link; 1131 char *fptr; 1132 struct ip *pip; 1133 1134 pip = (struct ip *) ptr; 1135 link = FindFragmentPtr(pip->ip_src, pip->ip_id); 1136 if (link != NULL) 1137 { 1138 GetFragmentPtr(link, &fptr); 1139 SetFragmentPtr(link, NULL); 1140 SetExpire(link, 0); /* Deletes link */ 1141 1142 return(fptr); 1143 } 1144 else 1145 { 1146 return(NULL); 1147 } 1148} 1149 1150 1151void 1152PacketAliasFragmentIn(char *ptr, /* Points to correctly de-aliased 1153 header fragment */ 1154 char *ptr_fragment /* Points to fragment which must 1155 be de-aliased */ 1156 ) 1157{ 1158 struct ip *pip; 1159 struct ip *fpip; 1160 1161 pip = (struct ip *) ptr; 1162 fpip = (struct ip *) ptr_fragment; 1163 1164 DifferentialChecksum(&fpip->ip_sum, 1165 (u_short *) &pip->ip_dst, 1166 (u_short *) &fpip->ip_dst, 1167 2); 1168 fpip->ip_dst = pip->ip_dst; 1169} 1170 1171 1172int 1173PacketAliasIn(char *ptr, int maxpacketsize) 1174{ 1175 struct in_addr alias_addr; 1176 struct ip *pip; 1177 int iresult; 1178 1179 if (packetAliasMode & PKT_ALIAS_REVERSE) { 1180 packetAliasMode &= ~PKT_ALIAS_REVERSE; 1181 iresult = PacketAliasOut(ptr, maxpacketsize); 1182 packetAliasMode |= PKT_ALIAS_REVERSE; 1183 return iresult; 1184 } 1185 1186 HouseKeeping(); 1187 ClearCheckNewLink(); 1188 pip = (struct ip *) ptr; 1189 alias_addr = pip->ip_dst; 1190 1191 /* Defense against mangled packets */ 1192 if (ntohs(pip->ip_len) > maxpacketsize 1193 || (pip->ip_hl<<2) > maxpacketsize) 1194 return PKT_ALIAS_IGNORED; 1195 1196 iresult = PKT_ALIAS_IGNORED; 1197 if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 ) 1198 { 1199 switch (pip->ip_p) 1200 { 1201 case IPPROTO_ICMP: 1202 iresult = IcmpAliasIn(pip); 1203 break; 1204 case IPPROTO_UDP: 1205 iresult = UdpAliasIn(pip); 1206 break; 1207 case IPPROTO_TCP: 1208 iresult = TcpAliasIn(pip); 1209 break; 1210 case IPPROTO_GRE: 1211 case IPPROTO_ESP: 1212 case IPPROTO_AH: 1213 iresult = PptpAliasIn(pip); 1214 break; 1215 } 1216 1217 if (ntohs(pip->ip_off) & IP_MF) 1218 { 1219 struct alias_link *link; 1220 1221 link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id); 1222 if (link != NULL) 1223 { 1224 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1225 SetFragmentAddr(link, pip->ip_dst); 1226 } 1227 else 1228 { 1229 iresult = PKT_ALIAS_ERROR; 1230 } 1231 } 1232 } 1233 else 1234 { 1235 iresult = FragmentIn(pip); 1236 } 1237 1238 return(iresult); 1239} 1240 1241 1242 1243/* Unregistered address ranges */ 1244 1245/* 10.0.0.0 -> 10.255.255.255 */ 1246#define UNREG_ADDR_A_LOWER 0x0a000000 1247#define UNREG_ADDR_A_UPPER 0x0affffff 1248 1249/* 172.16.0.0 -> 172.31.255.255 */ 1250#define UNREG_ADDR_B_LOWER 0xac100000 1251#define UNREG_ADDR_B_UPPER 0xac1fffff 1252 1253/* 192.168.0.0 -> 192.168.255.255 */ 1254#define UNREG_ADDR_C_LOWER 0xc0a80000 1255#define UNREG_ADDR_C_UPPER 0xc0a8ffff 1256 1257int 1258PacketAliasOut(char *ptr, /* valid IP packet */ 1259 int maxpacketsize /* How much the packet data may grow 1260 (FTP and IRC inline changes) */ 1261 ) 1262{ 1263 int iresult; 1264 struct in_addr addr_save; 1265 struct ip *pip; 1266 1267 if (packetAliasMode & PKT_ALIAS_REVERSE) { 1268 packetAliasMode &= ~PKT_ALIAS_REVERSE; 1269 iresult = PacketAliasIn(ptr, maxpacketsize); 1270 packetAliasMode |= PKT_ALIAS_REVERSE; 1271 return iresult; 1272 } 1273 1274 HouseKeeping(); 1275 ClearCheckNewLink(); 1276 pip = (struct ip *) ptr; 1277 1278 /* Defense against mangled packets */ 1279 if (ntohs(pip->ip_len) > maxpacketsize 1280 || (pip->ip_hl<<2) > maxpacketsize) 1281 return PKT_ALIAS_IGNORED; 1282 1283 addr_save = GetDefaultAliasAddress(); 1284 if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) 1285 { 1286 unsigned int addr; 1287 int iclass; 1288 1289 iclass = 0; 1290 addr = ntohl(pip->ip_src.s_addr); 1291 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1292 iclass = 3; 1293 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1294 iclass = 2; 1295 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1296 iclass = 1; 1297 1298 if (iclass == 0) 1299 { 1300 SetDefaultAliasAddress(pip->ip_src); 1301 } 1302 } 1303 1304 iresult = PKT_ALIAS_IGNORED; 1305 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) 1306 { 1307 switch (pip->ip_p) 1308 { 1309 case IPPROTO_ICMP: 1310 iresult = IcmpAliasOut(pip); 1311 break; 1312 case IPPROTO_UDP: 1313 iresult = UdpAliasOut(pip); 1314 break; 1315 case IPPROTO_TCP: 1316 iresult = TcpAliasOut(pip, maxpacketsize); 1317 break; 1318 case IPPROTO_GRE: 1319 case IPPROTO_ESP: 1320 case IPPROTO_AH: 1321 iresult = PptpAliasOut(pip); 1322 break; 1323 } 1324 } 1325 else 1326 { 1327 iresult = FragmentOut(pip); 1328 } 1329 1330 SetDefaultAliasAddress(addr_save); 1331 return(iresult); 1332} 1333