alias.c revision 29162
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*/ 77 78#include <stdio.h> 79#include <unistd.h> 80 81#include <sys/param.h> 82#include <sys/types.h> 83 84#include <netinet/in_systm.h> 85#include <netinet/in.h> 86#include <netinet/ip.h> 87#include <netinet/ip_icmp.h> 88#include <netinet/tcp.h> 89#include <netinet/udp.h> 90 91#include "alias_local.h" 92#include "alias.h" 93 94#define FTP_CONTROL_PORT_NUMBER 21 95#define IRC_CONTROL_PORT_NUMBER_1 6667 96#define IRC_CONTROL_PORT_NUMBER_2 6668 97 98/* 99 The following macro is used to update an 100 internet checksum. "delta" is a 32-bit 101 accumulation of all the changes to the 102 checksum (adding in new 16-bit words and 103 subtracting out old words), and "cksum" 104 is the checksum value to be updated. 105*/ 106#define ADJUST_CHECKSUM(acc, cksum) { \ 107 acc += cksum; \ 108 if (acc < 0) \ 109 { \ 110 acc = -acc; \ 111 acc = (acc >> 16) + (acc & 0xffff); \ 112 acc += acc >> 16; \ 113 cksum = (u_short) ~acc; \ 114 } \ 115 else \ 116 { \ 117 acc = (acc >> 16) + (acc & 0xffff); \ 118 acc += acc >> 16; \ 119 cksum = (u_short) acc; \ 120 } \ 121} 122 123 124 125 126/* TCP Handling Routines 127 128 TcpMonitorIn() -- These routines monitor TCP connections, and 129 TcpMonitorOut() -- delete a link node when a connection is closed. 130 131These routines look for SYN, ACK and RST flags to determine when TCP 132connections open and close. When a TCP connection closes, the data 133structure containing packet aliasing information is deleted after 134a timeout period. 135*/ 136 137/* Local prototypes */ 138static void TcpMonitorIn(struct ip *, struct alias_link *); 139 140static void TcpMonitorOut(struct ip *, struct alias_link *); 141 142 143static void 144TcpMonitorIn(struct ip *pip, struct alias_link *link) 145{ 146 struct tcphdr *tc; 147 148 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 149 150 switch (GetStateIn(link)) 151 { 152 case 0: 153 if (tc->th_flags & TH_SYN) SetStateIn(link, 1); 154 break; 155 case 1: 156 if (tc->th_flags & TH_FIN 157 || tc->th_flags & TH_RST) SetStateIn(link, 2); 158 } 159} 160 161static void 162TcpMonitorOut(struct ip *pip, struct alias_link *link) 163{ 164 struct tcphdr *tc; 165 166 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 167 168 switch (GetStateOut(link)) 169 { 170 case 0: 171 if (tc->th_flags & TH_SYN) SetStateOut(link, 1); 172 break; 173 case 1: 174 if (tc->th_flags & TH_FIN 175 || tc->th_flags & TH_RST) SetStateOut(link, 2); 176 } 177} 178 179 180 181 182 183/* Protocol Specific Packet Aliasing Routines 184 185 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3() 186 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3() 187 UdpAliasIn(), UdpAliasOut() 188 TcpAliasIn(), TcpAliasOut() 189 190These routines handle protocol specific details of packet aliasing. 191One may observe a certain amount of repetitive arithmetic in these 192functions, the purpose of which is to compute a revised checksum 193without actually summing over the entire data packet, which could be 194unnecessarily time consuming. 195 196The purpose of the packet aliasing routines is to replace the source 197address of the outgoing packet and then correctly put it back for 198any incoming packets. For TCP and UDP, ports are also re-mapped. 199 200For ICMP echo/timestamp requests and replies, the following scheme 201is used: the id number is replaced by an alias for the outgoing 202packet. 203 204ICMP error messages are handled by looking at the IP fragment 205in the data section of the message. 206 207For TCP and UDP protocols, a port number is chosen for an outgoing 208packet, and then incoming packets are identified by IP address and 209port numbers. For TCP packets, there is additional logic in the event 210that sequence and ack numbers have been altered (as is the case for 211FTP data port commands). 212 213The port numbers used by the packet aliasing module are not true 214ports in the Unix sense. No sockets are actually bound to ports. 215They are more correctly thought of as placeholders. 216 217All packets go through the aliasing mechanism, whether they come from 218the gateway machine or other machines on a local area network. 219*/ 220 221 222/* Local prototypes */ 223static int IcmpAliasIn1(struct ip *); 224static int IcmpAliasIn2(struct ip *); 225static int IcmpAliasIn3(struct ip *); 226static int IcmpAliasIn (struct ip *); 227 228static int IcmpAliasOut1(struct ip *); 229static int IcmpAliasOut2(struct ip *); 230static int IcmpAliasOut3(struct ip *); 231static int IcmpAliasOut (struct ip *); 232 233static int UdpAliasOut(struct ip *); 234static int UdpAliasIn (struct ip *); 235 236static int TcpAliasOut(struct ip *, int); 237static int TcpAliasIn (struct ip *); 238 239 240static int 241IcmpAliasIn1(struct ip *pip) 242{ 243/* 244 De-alias incoming echo and timestamp replies 245*/ 246 struct alias_link *link; 247 struct icmp *ic; 248 249 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 250 251/* Get source address from ICMP data field and restore original data */ 252 link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id); 253 if (link != NULL) 254 { 255 u_short original_id; 256 int accumulate; 257 258 original_id = GetOriginalPort(link); 259 260/* Adjust ICMP checksum */ 261 accumulate = ic->icmp_id; 262 accumulate -= original_id; 263 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 264 265/* Put original sequence number back in */ 266 ic->icmp_id = original_id; 267 268/* Put original address back into IP header */ 269 { 270 struct in_addr original_address; 271 272 original_address = GetOriginalAddress(link); 273 DifferentialChecksum(&pip->ip_sum, 274 (u_short *) &original_address, 275 (u_short *) &pip->ip_dst, 276 2); 277 pip->ip_dst = original_address; 278 } 279 280 return(PKT_ALIAS_OK); 281 } 282 return(PKT_ALIAS_IGNORED); 283} 284 285static int 286IcmpAliasIn2(struct ip *pip) 287{ 288/* 289 Alias incoming ICMP error messages containing 290 IP header and first 64 bits of datagram. 291*/ 292 struct ip *ip; 293 struct icmp *ic, *ic2; 294 struct udphdr *ud; 295 struct tcphdr *tc; 296 struct alias_link *link; 297 298 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 299 ip = (struct ip *) ic->icmp_data; 300 301 ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); 302 tc = (struct tcphdr *) ud; 303 ic2 = (struct icmp *) ud; 304 305 if (ip->ip_p == IPPROTO_UDP) 306 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, 307 ud->uh_dport, ud->uh_sport, 308 IPPROTO_UDP); 309 else if (ip->ip_p == IPPROTO_TCP) 310 link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, 311 tc->th_dport, tc->th_sport, 312 IPPROTO_TCP); 313 else if (ip->ip_p == IPPROTO_ICMP) 314 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 315 link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id); 316 else 317 link = NULL; 318 else 319 link = NULL; 320 321 if (link != NULL) 322 { 323 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) 324 { 325 u_short *sptr; 326 int accumulate; 327 struct in_addr original_address; 328 u_short original_port; 329 330 original_address = GetOriginalAddress(link); 331 original_port = GetOriginalPort(link); 332 333/* Adjust ICMP checksum */ 334 sptr = (u_short *) &(ip->ip_src); 335 accumulate = *sptr++; 336 accumulate += *sptr; 337 sptr = (u_short *) &original_address; 338 accumulate -= *sptr++; 339 accumulate -= *sptr; 340 accumulate += ud->uh_sport; 341 accumulate -= original_port; 342 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 343 344/* Un-alias address in IP header */ 345 DifferentialChecksum(&pip->ip_sum, 346 (u_short *) &original_address, 347 (u_short *) &pip->ip_dst, 348 2); 349 pip->ip_dst = original_address; 350 351/* Un-alias address and port number of original IP packet 352fragment contained in ICMP data section */ 353 ip->ip_src = original_address; 354 ud->uh_sport = original_port; 355 } 356 else if (pip->ip_p == IPPROTO_ICMP) 357 { 358 u_short *sptr; 359 int accumulate; 360 struct in_addr original_address; 361 u_short original_id; 362 363 original_address = GetOriginalAddress(link); 364 original_id = GetOriginalPort(link); 365 366/* Adjust ICMP checksum */ 367 sptr = (u_short *) &(ip->ip_src); 368 accumulate = *sptr++; 369 accumulate += *sptr; 370 sptr = (u_short *) &original_address; 371 accumulate -= *sptr++; 372 accumulate -= *sptr; 373 accumulate += ic2->icmp_id; 374 accumulate -= original_id; 375 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 376 377/* Un-alias address in IP header */ 378 DifferentialChecksum(&pip->ip_sum, 379 (u_short *) &original_address, 380 (u_short *) &pip->ip_dst, 381 2); 382 pip->ip_dst = original_address; 383 384/* Un-alias address of original IP packet and seqence number of 385 embedded icmp datagram */ 386 ip->ip_src = original_address; 387 ic2->icmp_id = original_id; 388 } 389 return(PKT_ALIAS_OK); 390 } 391 return(PKT_ALIAS_IGNORED); 392} 393 394 395static int 396IcmpAliasIn3(struct ip *pip) 397{ 398 struct in_addr original_address; 399 400 original_address = FindOriginalAddress(pip->ip_dst); 401 DifferentialChecksum(&pip->ip_sum, 402 (u_short *) &original_address, 403 (u_short *) &pip->ip_dst, 404 2); 405 pip->ip_dst = original_address; 406 407 return PKT_ALIAS_OK; 408} 409 410 411static int 412IcmpAliasIn(struct ip *pip) 413{ 414 int iresult; 415 struct icmp *ic; 416 417 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 418 419 iresult = PKT_ALIAS_IGNORED; 420 switch (ic->icmp_type) 421 { 422 case ICMP_ECHOREPLY: 423 case ICMP_TSTAMPREPLY: 424 if (ic->icmp_code == 0) 425 { 426 iresult = IcmpAliasIn1(pip); 427 } 428 break; 429 case ICMP_UNREACH: 430 case ICMP_SOURCEQUENCH: 431 case ICMP_TIMXCEED: 432 case ICMP_PARAMPROB: 433 iresult = IcmpAliasIn2(pip); 434 break; 435 case ICMP_ECHO: 436 case ICMP_TSTAMP: 437 iresult = IcmpAliasIn3(pip); 438 break; 439 } 440 return(iresult); 441} 442 443 444static int 445IcmpAliasOut1(struct ip *pip) 446{ 447/* 448 Alias ICMP echo and timestamp packets 449*/ 450 struct alias_link *link; 451 struct icmp *ic; 452 453 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 454 455/* Save overwritten data for when echo packet returns */ 456 link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id); 457 if (link != NULL) 458 { 459 u_short alias_id; 460 int accumulate; 461 462 alias_id = GetAliasPort(link); 463 464/* Since data field is being modified, adjust ICMP checksum */ 465 accumulate = ic->icmp_id; 466 accumulate -= alias_id; 467 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) 468 469/* Alias sequence number */ 470 ic->icmp_id = alias_id; 471 472/* Change source address */ 473 { 474 struct in_addr alias_address; 475 476 alias_address = GetAliasAddress(link); 477 DifferentialChecksum(&pip->ip_sum, 478 (u_short *) &alias_address, 479 (u_short *) &pip->ip_src, 480 2); 481 pip->ip_src = alias_address; 482 } 483 484 return(PKT_ALIAS_OK); 485 } 486 return(PKT_ALIAS_IGNORED); 487} 488 489 490static int 491IcmpAliasOut2(struct ip *pip) 492{ 493/* 494 Alias outgoing ICMP error messages containing 495 IP header and first 64 bits of datagram. 496*/ 497 struct in_addr alias_addr; 498 struct ip *ip; 499 struct icmp *ic; 500 501 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 502 ip = (struct ip *) ic->icmp_data; 503 504 alias_addr = FindAliasAddress(ip->ip_src); 505 506/* Alias destination address in IP fragment */ 507 DifferentialChecksum(&ic->icmp_cksum, 508 (u_short *) &alias_addr, 509 (u_short *) &ip->ip_dst, 510 2); 511 ip->ip_dst = alias_addr; 512 513/* alias source address in IP header */ 514 DifferentialChecksum(&pip->ip_sum, 515 (u_short *) &alias_addr, 516 (u_short *) &pip->ip_src, 517 2); 518 pip->ip_src = alias_addr; 519 520 return PKT_ALIAS_OK; 521} 522 523 524static int 525IcmpAliasOut3(struct ip *pip) 526{ 527/* 528 Handle outgoing echo and timestamp replies. The 529 only thing which is done in this case is to alias 530 the source IP address of the packet. 531*/ 532 struct in_addr alias_addr; 533 534 alias_addr = FindAliasAddress(pip->ip_src); 535 DifferentialChecksum(&pip->ip_sum, 536 (u_short *) &alias_addr, 537 (u_short *) &pip->ip_src, 538 2); 539 pip->ip_src = alias_addr; 540 541 return PKT_ALIAS_OK; 542} 543 544 545static int 546IcmpAliasOut(struct ip *pip) 547{ 548 int iresult; 549 struct icmp *ic; 550 551 ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); 552 553 iresult = PKT_ALIAS_IGNORED; 554 switch (ic->icmp_type) 555 { 556 case ICMP_ECHO: 557 case ICMP_TSTAMP: 558 if (ic->icmp_code == 0) 559 { 560 iresult = IcmpAliasOut1(pip); 561 } 562 break; 563 case ICMP_UNREACH: 564 case ICMP_SOURCEQUENCH: 565 case ICMP_TIMXCEED: 566 case ICMP_PARAMPROB: 567 iresult = IcmpAliasOut2(pip); 568 break; 569 case ICMP_ECHOREPLY: 570 case ICMP_TSTAMPREPLY: 571 iresult = IcmpAliasOut3(pip); 572 } 573 return(iresult); 574} 575 576static int 577UdpAliasIn(struct ip *pip) 578{ 579 struct udphdr *ud; 580 struct alias_link *link; 581 582 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 583 584 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, 585 ud->uh_sport, ud->uh_dport, 586 IPPROTO_UDP); 587 if (link != NULL) 588 { 589 struct in_addr alias_address; 590 struct in_addr original_address; 591 u_short alias_port; 592 int accumulate; 593 u_short *sptr; 594 595 alias_address = GetAliasAddress(link); 596 original_address = GetOriginalAddress(link); 597 alias_port = ud->uh_dport; 598 ud->uh_dport = GetOriginalPort(link); 599 600/* If UDP checksum is not zero, then adjust since destination port */ 601/* is being unaliased and destination port is being altered. */ 602 if (ud->uh_sum != 0) 603 { 604 accumulate = alias_port; 605 accumulate -= ud->uh_dport; 606 sptr = (u_short *) &alias_address; 607 accumulate += *sptr++; 608 accumulate += *sptr; 609 sptr = (u_short *) &original_address; 610 accumulate -= *sptr++; 611 accumulate -= *sptr; 612 ADJUST_CHECKSUM(accumulate, ud->uh_sum) 613 } 614 615/* Restore original IP address */ 616 DifferentialChecksum(&pip->ip_sum, 617 (u_short *) &original_address, 618 (u_short *) &pip->ip_dst, 619 2); 620 pip->ip_dst = original_address; 621 return(PKT_ALIAS_OK); 622 } 623 return(PKT_ALIAS_IGNORED); 624} 625 626static int 627UdpAliasOut(struct ip *pip) 628{ 629 struct udphdr *ud; 630 struct alias_link *link; 631 632 ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 633 634 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, 635 ud->uh_sport, ud->uh_dport, 636 IPPROTO_UDP); 637 if (link != NULL) 638 { 639 u_short alias_port; 640 struct in_addr alias_address; 641 642 alias_address = GetAliasAddress(link); 643 alias_port = GetAliasPort(link); 644 645/* If UDP checksum is not zero, adjust since source port is */ 646/* being aliased and source address is being altered */ 647 if (ud->uh_sum != 0) 648 { 649 int accumulate; 650 u_short *sptr; 651 652 accumulate = ud->uh_sport; 653 accumulate -= alias_port; 654 sptr = (u_short *) &(pip->ip_src); 655 accumulate += *sptr++; 656 accumulate += *sptr; 657 sptr = (u_short *) &alias_address; 658 accumulate -= *sptr++; 659 accumulate -= *sptr; 660 ADJUST_CHECKSUM(accumulate, ud->uh_sum) 661 } 662 663/* Put alias port in TCP header */ 664 ud->uh_sport = alias_port; 665 666/* Change source address */ 667 DifferentialChecksum(&pip->ip_sum, 668 (u_short *) &alias_address, 669 (u_short *) &pip->ip_src, 670 2); 671 pip->ip_src = alias_address; 672 673 return(PKT_ALIAS_OK); 674 } 675 return(PKT_ALIAS_IGNORED); 676} 677 678 679 680static int 681TcpAliasIn(struct ip *pip) 682{ 683 struct tcphdr *tc; 684 struct alias_link *link; 685 686 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 687 688 link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, 689 tc->th_sport, tc->th_dport, 690 IPPROTO_TCP); 691 if (link != NULL) 692 { 693 struct in_addr alias_address; 694 struct in_addr original_address; 695 u_short alias_port; 696 int accumulate; 697 u_short *sptr; 698 699 alias_address = GetAliasAddress(link); 700 original_address = GetOriginalAddress(link); 701 alias_port = tc->th_dport; 702 tc->th_dport = GetOriginalPort(link); 703 704/* Adjust TCP checksum since destination port is being unaliased */ 705/* and destination port is being altered. */ 706 accumulate = alias_port; 707 accumulate -= tc->th_dport; 708 sptr = (u_short *) &alias_address; 709 accumulate += *sptr++; 710 accumulate += *sptr; 711 sptr = (u_short *) &original_address; 712 accumulate -= *sptr++; 713 accumulate -= *sptr; 714 715/* See if ack number needs to be modified */ 716 if (GetAckModified(link) == 1) 717 { 718 int delta; 719 720 delta = GetDeltaAckIn(pip, link); 721 if (delta != 0) 722 { 723 sptr = (u_short *) &tc->th_ack; 724 accumulate += *sptr++; 725 accumulate += *sptr; 726 tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 727 sptr = (u_short *) &tc->th_ack; 728 accumulate -= *sptr++; 729 accumulate -= *sptr; 730 } 731 } 732 733 ADJUST_CHECKSUM(accumulate, tc->th_sum); 734 735/* Restore original IP address */ 736 DifferentialChecksum(&pip->ip_sum, 737 (u_short *) &original_address, 738 (u_short *) &pip->ip_dst, 739 2); 740 pip->ip_dst = original_address; 741 742/* Monitor TCP connection state */ 743 TcpMonitorIn(pip, link); 744 745 return(PKT_ALIAS_OK); 746 } 747 return(PKT_ALIAS_IGNORED); 748} 749 750static int 751TcpAliasOut(struct ip *pip, int maxpacketsize) 752{ 753 struct tcphdr *tc; 754 struct alias_link *link; 755 756 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 757 758 link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, 759 tc->th_sport, tc->th_dport, 760 IPPROTO_TCP); 761 if (link !=NULL) 762 { 763 struct in_addr alias_address; 764 u_short alias_port; 765 int accumulate; 766 u_short *sptr; 767 768 alias_port = GetAliasPort(link); 769 alias_address = GetAliasAddress(link); 770 771/* Monitor tcp connection state */ 772 TcpMonitorOut(pip, link); 773 774/* Special processing for ftp connection */ 775 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER 776 || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER) 777 AliasHandleFtpOut(pip, link, maxpacketsize); 778 if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 779 || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2) 780 AliasHandleIrcOut(pip, link, maxpacketsize); 781 782/* Adjust TCP checksum since source port is being aliased */ 783/* and source address is being altered */ 784 accumulate = tc->th_sport; 785 accumulate -= alias_port; 786 sptr = (u_short *) &(pip->ip_src); 787 accumulate += *sptr++; 788 accumulate += *sptr; 789 sptr = (u_short *) &alias_address; 790 accumulate -= *sptr++; 791 accumulate -= *sptr; 792 793/* Modify sequence number if necessary */ 794 if (GetAckModified(link) == 1) 795 { 796 int delta; 797 798 delta = GetDeltaSeqOut(pip, link); 799 if (delta != 0) 800 { 801 sptr = (u_short *) &tc->th_seq; 802 accumulate += *sptr++; 803 accumulate += *sptr; 804 tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 805 sptr = (u_short *) &tc->th_seq; 806 accumulate -= *sptr++; 807 accumulate -= *sptr; 808 } 809 } 810 811 ADJUST_CHECKSUM(accumulate, tc->th_sum) 812 813/* Put alias address in TCP header */ 814 tc->th_sport = alias_port; 815 816/* Change source address */ 817 DifferentialChecksum(&pip->ip_sum, 818 (u_short *) &alias_address, 819 (u_short *) &pip->ip_src, 820 2); 821 pip->ip_src = alias_address; 822 823 return(PKT_ALIAS_OK); 824 } 825 return(PKT_ALIAS_IGNORED); 826} 827 828 829 830 831/* Fragment Handling 832 833 FragmentIn() 834 FragmentOut() 835 836The packet aliasing module has a limited ability for handling IP 837fragments. If the ICMP, TCP or UDP header is in the first fragment 838received, then the id number of the IP packet is saved, and other 839fragments are identified according to their ID number and IP address 840they were sent from. Pointers to unresolved fragments can also be 841saved and recalled when a header fragment is seen. 842*/ 843 844/* Local prototypes */ 845static int FragmentIn(struct ip *); 846static int FragmentOut(struct ip *); 847 848 849static int 850FragmentIn(struct ip *pip) 851{ 852 struct alias_link *link; 853 854 link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id); 855 if (link != NULL) 856 { 857 struct in_addr original_address; 858 859 GetFragmentAddr(link, &original_address); 860 DifferentialChecksum(&pip->ip_sum, 861 (u_short *) &original_address, 862 (u_short *) &pip->ip_dst, 863 2); 864 pip->ip_dst = original_address; 865 866 return(PKT_ALIAS_OK); 867 } 868 return(PKT_ALIAS_UNRESOLVED_FRAGMENT); 869} 870 871 872static int 873FragmentOut(struct ip *pip) 874{ 875 struct in_addr alias_address; 876 877 alias_address = FindAliasAddress(pip->ip_src); 878 DifferentialChecksum(&pip->ip_sum, 879 (u_short *) &alias_address, 880 (u_short *) &pip->ip_src, 881 2); 882 pip->ip_src = alias_address; 883 884 return(PKT_ALIAS_OK); 885} 886 887 888 889 890 891 892/* Outside World Access 893 894 PacketAliasSaveFragment() 895 PacketAliasGetFragment() 896 PacketAliasFragmentIn() 897 PacketAliasIn() 898 PacketAliasOut() 899 900(prototypes in alias.h) 901*/ 902 903 904int 905PacketAliasSaveFragment(char *ptr) 906{ 907 int iresult; 908 struct alias_link *link; 909 struct ip *pip; 910 911 pip = (struct ip *) ptr; 912 link = AddFragmentPtrLink(pip->ip_src, pip->ip_id); 913 iresult = PKT_ALIAS_ERROR; 914 if (link != NULL) 915 { 916 SetFragmentPtr(link, ptr); 917 iresult = PKT_ALIAS_OK; 918 } 919 return(iresult); 920} 921 922 923char * 924PacketAliasGetFragment(char *ptr) 925{ 926 struct alias_link *link; 927 char *fptr; 928 struct ip *pip; 929 930 pip = (struct ip *) ptr; 931 link = FindFragmentPtr(pip->ip_src, pip->ip_id); 932 if (link != NULL) 933 { 934 GetFragmentPtr(link, &fptr); 935 SetFragmentPtr(link, NULL); 936 SetExpire(link, 0); /* Deletes link */ 937 938 return(fptr); 939 } 940 else 941 { 942 return(NULL); 943 } 944} 945 946 947void 948PacketAliasFragmentIn(char *ptr, /* Points to correctly de-aliased 949 header fragment */ 950 char *ptr_fragment /* Points to fragment which must 951 be de-aliased */ 952 ) 953{ 954 struct ip *pip; 955 struct ip *fpip; 956 957 pip = (struct ip *) ptr; 958 fpip = (struct ip *) ptr_fragment; 959 960 DifferentialChecksum(&fpip->ip_sum, 961 (u_short *) &pip->ip_dst, 962 (u_short *) &fpip->ip_dst, 963 2); 964 fpip->ip_dst = pip->ip_dst; 965} 966 967 968int 969PacketAliasIn(char *ptr, int maxpacketsize) 970{ 971 struct in_addr alias_addr; 972 struct ip *pip; 973 int iresult; 974 975 HouseKeeping(); 976 ClearCheckNewLink(); 977 pip = (struct ip *) ptr; 978 alias_addr = pip->ip_dst; 979 980 iresult = PKT_ALIAS_IGNORED; 981 if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 ) 982 { 983 switch (pip->ip_p) 984 { 985 case IPPROTO_ICMP: 986 iresult = IcmpAliasIn(pip); 987 break; 988 case IPPROTO_UDP: 989 iresult = UdpAliasIn(pip); 990 break; 991 case IPPROTO_TCP: 992 iresult = TcpAliasIn(pip); 993 break; 994 } 995 996 if (ntohs(pip->ip_off) & IP_MF) 997 { 998 struct alias_link *link; 999 1000 link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id); 1001 if (link != NULL) 1002 { 1003 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1004 SetFragmentAddr(link, pip->ip_dst); 1005 } 1006 else 1007 { 1008 iresult = PKT_ALIAS_ERROR; 1009 } 1010 } 1011 } 1012 else 1013 { 1014 iresult = FragmentIn(pip); 1015 } 1016 1017 return(iresult); 1018} 1019 1020 1021 1022/* Unregistered address ranges */ 1023 1024/* 10.0.0.0 -> 10.255.255.255 */ 1025#define UNREG_ADDR_A_LOWER 0x0a000000 1026#define UNREG_ADDR_A_UPPER 0x0affffff 1027 1028/* 172.16.0.0 -> 172.31.255.255 */ 1029#define UNREG_ADDR_B_LOWER 0xac100000 1030#define UNREG_ADDR_B_UPPER 0xac1fffff 1031 1032/* 192.168.0.0 -> 192.168.255.255 */ 1033#define UNREG_ADDR_C_LOWER 0xc0a80000 1034#define UNREG_ADDR_C_UPPER 0xc0a8ffff 1035 1036 1037 1038int 1039PacketAliasOut(char *ptr, /* valid IP packet */ 1040 int maxpacketsize /* How much the packet data may grow 1041 (FTP and IRC inline changes) */ 1042 ) 1043{ 1044 int iresult; 1045 struct in_addr addr_save; 1046 struct ip *pip; 1047 1048 HouseKeeping(); 1049 ClearCheckNewLink(); 1050 pip = (struct ip *) ptr; 1051 1052 addr_save = GetDefaultAliasAddress(); 1053 if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) 1054 { 1055 unsigned int addr; 1056 int iclass; 1057 1058 iclass = 0; 1059 addr = ntohl(pip->ip_src.s_addr); 1060 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1061 iclass = 3; 1062 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1063 iclass = 2; 1064 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1065 iclass = 1; 1066 1067 if (iclass == 0) 1068 { 1069 SetDefaultAliasAddress(pip->ip_src); 1070 } 1071 } 1072 1073 iresult = PKT_ALIAS_IGNORED; 1074 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) 1075 { 1076 switch (pip->ip_p) 1077 { 1078 case IPPROTO_ICMP: 1079 iresult = IcmpAliasOut(pip); 1080 break; 1081 case IPPROTO_UDP: 1082 iresult = UdpAliasOut(pip); 1083 break; 1084 case IPPROTO_TCP: 1085 iresult = TcpAliasOut(pip, maxpacketsize); 1086 break; 1087 } 1088 } 1089 else 1090 { 1091 iresult = FragmentOut(pip); 1092 } 1093 1094 SetDefaultAliasAddress(addr_save); 1095 return(iresult); 1096} 1097