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