1/*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*-
23 * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 *    notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 *    notice, this list of conditions and the following disclaimer in the
33 *    documentation and/or other materials provided with the distribution.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 *
47 * Based upon:
48 * $FreeBSD: src/lib/libalias/alias.c,v 1.16.2.7 2001/08/21 03:50:25 brian Exp $
49 */
50
51/*
52    Alias.c provides supervisory control for the functions of the
53    packet aliasing software.  It consists of routines to monitor
54    TCP connection state, protocol-specific aliasing routines,
55    fragment handling and the following outside world functional
56    interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
57    PacketAliasIn and PacketAliasOut.
58
59    The other C program files are briefly described. The data
60    structure framework which holds information needed to translate
61    packets is encapsulated in alias_db.c.  Data is accessed by
62    function calls, so other segments of the program need not know
63    about the underlying data structures.  Alias_ftp.c contains
64    special code for modifying the ftp PORT command used to establish
65    data connections, while alias_irc.c does the same for IRC
66    DCC. Alias_util.c contains a few utility routines.
67
68    Version 1.0 August, 1996  (cjm)
69
70    Version 1.1 August 20, 1996  (cjm)
71        PPP host accepts incoming connections for ports 0 to 1023.
72        (Gary Roberts pointed out the need to handle incoming
73         connections.)
74
75    Version 1.2 September 7, 1996 (cjm)
76        Fragment handling error in alias_db.c corrected.
77        (Tom Torrance helped fix this problem.)
78
79    Version 1.4 September 16, 1996 (cjm)
80        - A more generalized method for handling incoming
81          connections, without the 0-1023 restriction, is
82          implemented in alias_db.c
83        - Improved ICMP support in alias.c.  Traceroute
84          packet streams can now be correctly aliased.
85        - TCP connection closing logic simplified in
86          alias.c and now allows for additional 1 minute
87          "grace period" after FIN or RST is observed.
88
89    Version 1.5 September 17, 1996 (cjm)
90        Corrected error in handling incoming UDP packets with 0 checksum.
91        (Tom Torrance helped fix this problem.)
92
93    Version 1.6 September 18, 1996 (cjm)
94        Simplified ICMP aliasing scheme.  Should now support
95        traceroute from Win95 as well as FreeBSD.
96
97    Version 1.7 January 9, 1997 (cjm)
98        - Out-of-order fragment handling.
99        - IP checksum error fixed for ftp transfers
100          from aliasing host.
101        - Integer return codes added to all
102          aliasing/de-aliasing functions.
103        - Some obsolete comments cleaned up.
104        - Differential checksum computations for
105          IP header (TCP, UDP and ICMP were already
106          differential).
107
108    Version 2.1 May 1997 (cjm)
109        - Added support for outgoing ICMP error
110          messages.
111        - Added two functions PacketAliasIn2()
112          and PacketAliasOut2() for dynamic address
113          control (e.g. round-robin allocation of
114          incoming packets).
115
116    Version 2.2 July 1997 (cjm)
117        - Rationalized API function names to begin
118          with "PacketAlias..."
119        - Eliminated PacketAliasIn2() and
120          PacketAliasOut2() as poorly conceived.
121
122    Version 2.3 Dec 1998 (dillon)
123	- Major bounds checking additions, see FreeBSD/CVS
124
125    Version 3.1 May, 2000 (salander)
126	- Added hooks to handle PPTP.
127
128    Version 3.2 July, 2000 (salander and satoh)
129	- Added PacketUnaliasOut routine.
130	- Added hooks to handle RTSP/RTP.
131
132    See HISTORY file for additional revisions.
133*/
134
135#include <sys/types.h>
136
137#include <netinet/in_systm.h>
138#include <netinet/in.h>
139#include <netinet/ip.h>
140#include <netinet/ip_icmp.h>
141#include <netinet/tcp.h>
142#include <netinet/udp.h>
143
144#include <stdio.h>
145
146#include "alias_local.h"
147#include "alias.h"
148
149#define NETBIOS_NS_PORT_NUMBER 137
150#define NETBIOS_DGM_PORT_NUMBER 138
151#define FTP_CONTROL_PORT_NUMBER 21
152#define IRC_CONTROL_PORT_NUMBER_1 6667
153#define IRC_CONTROL_PORT_NUMBER_2 6668
154#define CUSEEME_PORT_NUMBER 7648
155#define RTSP_CONTROL_PORT_NUMBER_1 554
156#define RTSP_CONTROL_PORT_NUMBER_2 7070
157#define PPTP_CONTROL_PORT_NUMBER 1723
158
159
160
161
162/* TCP Handling Routines
163
164    TcpMonitorIn()  -- These routines monitor TCP connections, and
165    TcpMonitorOut()    delete a link when a connection is closed.
166
167	DoMSSClamp()    -- Clamps the MSS of the given TCP header to the
168                       value in packetAliasMSS.
169
170These routines look for SYN, FIN and RST flags to determine when TCP
171connections open and close.  When a TCP connection closes, the data
172structure containing packet aliasing information is deleted after
173a timeout period.
174*/
175
176/* Local prototypes */
177static void TcpMonitorIn(struct ip *, struct alias_link *);
178
179static void TcpMonitorOut(struct ip *, struct alias_link *);
180
181
182static u_short packetAliasMSS;
183
184void PacketAliasClampMSS(u_short mss)
185{
186    packetAliasMSS = mss;
187}
188
189static void DoMSSClamp(struct tcphdr *tc)
190{
191    u_char *option    = (u_char *) tc + sizeof(*tc);
192    u_char *optionEnd = option + ((tc->th_off << 2) - sizeof(*tc));
193
194#define TEST_5618045 0
195#if TEST_5618045
196	if ((ntohs(tc->th_dport) == 8080 || ntohs(tc->th_sport) == 8080) && tc->th_off > 5) {
197		option[0] = 0xF4;
198		option[1] = 0;
199	}
200#endif
201
202    while (optionEnd > option)
203    {
204        /* Bounds checking to avoid infinite loops */
205        if (option[0] == TCPOPT_EOL)
206            break;
207
208        if (option[0] == TCPOPT_NOP) {
209            ++option;
210            continue;
211        } else {
212            if (optionEnd - option < 2)
213                break;
214            if (option[1] < 2 || option + option[1] >= optionEnd)
215                break;
216    	}
217
218        switch (option[0])
219        {
220            case TCPOPT_MAXSEG:
221                if (option[1] == 4)
222                {
223                    u_short *mssPtr = (u_short *) option + 1;
224                    u_short mssVal  = ntohs(*mssPtr);
225
226                    if (packetAliasMSS < mssVal)
227                    {
228                        int accumulate = mssVal;
229                        int accnetorder = 0 ;
230
231                        accumulate -= packetAliasMSS;
232                        *mssPtr = htons(packetAliasMSS);
233                        accnetorder = htons(accumulate);
234                        ADJUST_CHECKSUM(accnetorder, tc->th_sum);
235                    }
236
237                    option = optionEnd;
238                }
239                break;
240
241            default:
242                option += option[1];
243                break;
244        }
245    }
246}
247
248static void
249TcpMonitorIn(struct ip *pip, struct alias_link *link)
250{
251    struct tcphdr *tc;
252
253    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
254
255    switch (GetStateIn(link))
256    {
257        case ALIAS_TCP_STATE_NOT_CONNECTED:
258            if (tc->th_flags & TH_RST)
259                SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
260            else if (tc->th_flags & TH_SYN)
261            {
262                SetStateIn(link, ALIAS_TCP_STATE_CONNECTED);
263
264                if (packetAliasMSS)
265                    DoMSSClamp(tc);
266            }
267            break;
268        case ALIAS_TCP_STATE_CONNECTED:
269            if (tc->th_flags & (TH_FIN | TH_RST))
270                SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
271            break;
272    }
273}
274
275static void
276TcpMonitorOut(struct ip *pip, struct alias_link *link)
277{
278    struct tcphdr *tc;
279
280    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
281
282    switch (GetStateOut(link))
283    {
284        case ALIAS_TCP_STATE_NOT_CONNECTED:
285            if (tc->th_flags & TH_RST)
286                SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
287            else if (tc->th_flags & TH_SYN)
288            {
289                SetStateOut(link, ALIAS_TCP_STATE_CONNECTED);
290
291                if (packetAliasMSS)
292                    DoMSSClamp(tc);
293            }
294            break;
295        case ALIAS_TCP_STATE_CONNECTED:
296            if (tc->th_flags & (TH_FIN | TH_RST))
297                SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
298            break;
299    }
300}
301
302
303
304
305
306/* Protocol Specific Packet Aliasing Routines
307
308    IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
309    IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
310    ProtoAliasIn(), ProtoAliasOut()
311    UdpAliasIn(), UdpAliasOut()
312    TcpAliasIn(), TcpAliasOut()
313
314These routines handle protocol specific details of packet aliasing.
315One may observe a certain amount of repetitive arithmetic in these
316functions, the purpose of which is to compute a revised checksum
317without actually summing over the entire data packet, which could be
318unnecessarily time consuming.
319
320The purpose of the packet aliasing routines is to replace the source
321address of the outgoing packet and then correctly put it back for
322any incoming packets.  For TCP and UDP, ports are also re-mapped.
323
324For ICMP echo/timestamp requests and replies, the following scheme
325is used: the ID number is replaced by an alias for the outgoing
326packet.
327
328ICMP error messages are handled by looking at the IP fragment
329in the data section of the message.
330
331For TCP and UDP protocols, a port number is chosen for an outgoing
332packet, and then incoming packets are identified by IP address and
333port numbers.  For TCP packets, there is additional logic in the event
334that sequence and ACK numbers have been altered (as in the case for
335FTP data port commands).
336
337The port numbers used by the packet aliasing module are not true
338ports in the Unix sense.  No sockets are actually bound to ports.
339They are more correctly thought of as placeholders.
340
341All packets go through the aliasing mechanism, whether they come from
342the gateway machine or other machines on a local area network.
343*/
344
345
346/* Local prototypes */
347static int IcmpAliasIn1(struct ip *);
348static int IcmpAliasIn2(struct ip *);
349static int IcmpAliasIn (struct ip *);
350
351static int IcmpAliasOut1(struct ip *);
352static int IcmpAliasOut2(struct ip *);
353static int IcmpAliasOut (struct ip *);
354
355static int ProtoAliasIn(struct ip *);
356static int ProtoAliasOut(struct ip *);
357
358static int UdpAliasOut(struct ip *);
359static int UdpAliasIn (struct ip *);
360
361static int TcpAliasOut(struct ip *, int);
362static int TcpAliasIn (struct ip *);
363
364
365static int
366IcmpAliasIn1(struct ip *pip)
367{
368/*
369    De-alias incoming echo and timestamp replies.
370    Alias incoming echo and timestamp requests.
371*/
372    struct alias_link *link;
373    struct icmp *ic;
374
375    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
376
377/* Get source address from ICMP data field and restore original data */
378    link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
379    if (link != NULL)
380    {
381        u_short original_id;
382        int accumulate;
383
384        original_id = GetOriginalPort(link);
385
386/* Adjust ICMP checksum */
387        accumulate  = ic->icmp_id;
388        accumulate -= original_id;
389        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
390
391/* Put original sequence number back in */
392        ic->icmp_id = original_id;
393
394/* Put original address back into IP header */
395        {
396            struct in_addr original_address;
397
398            original_address = GetOriginalAddress(link);
399            DifferentialChecksum(&pip->ip_sum,
400                                 (u_short *) &original_address,
401                                 (u_short *) &pip->ip_dst,
402                                 2);
403            pip->ip_dst = original_address;
404        }
405
406        return(PKT_ALIAS_OK);
407    }
408    return(PKT_ALIAS_IGNORED);
409}
410
411static int
412IcmpAliasIn2(struct ip *pip)
413{
414/*
415    Alias incoming ICMP error messages containing
416    IP header and first 64 bits of datagram.
417*/
418    struct ip *ip;
419    struct icmp *ic, *ic2;
420    struct udphdr *ud;
421    struct tcphdr *tc;
422    struct alias_link *link;
423
424    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
425    ip = &ic->icmp_ip;
426
427    ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
428    tc = (struct tcphdr *) ud;
429    ic2 = (struct icmp *) ud;
430
431    if (ip->ip_p == IPPROTO_UDP)
432        link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
433                            ud->uh_dport, ud->uh_sport,
434                            IPPROTO_UDP, 0);
435    else if (ip->ip_p == IPPROTO_TCP)
436        link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
437                            tc->th_dport, tc->th_sport,
438                            IPPROTO_TCP, 0);
439    else if (ip->ip_p == IPPROTO_ICMP) {
440        if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
441            link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
442        else
443            link = NULL;
444    } else
445        link = NULL;
446
447    if (link != NULL)
448    {
449        if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
450        {
451            u_short *sptr;
452            int accumulate;
453            struct in_addr original_address;
454            u_short original_port;
455
456            original_address = GetOriginalAddress(link);
457            original_port = GetOriginalPort(link);
458
459/* Adjust ICMP checksum */
460            sptr = (u_short *) &(ip->ip_src);
461            accumulate  = *sptr++;
462            accumulate += *sptr;
463            sptr = (u_short *) &original_address;
464            accumulate -= *sptr++;
465            accumulate -= *sptr;
466            accumulate += ud->uh_sport;
467            accumulate -= original_port;
468            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
469
470/* Un-alias address in IP header */
471            DifferentialChecksum(&pip->ip_sum,
472                                 (u_short *) &original_address,
473                                 (u_short *) &pip->ip_dst,
474                                 2);
475            pip->ip_dst = original_address;
476
477/* Un-alias address and port number of original IP packet
478fragment contained in ICMP data section */
479            ip->ip_src = original_address;
480            ud->uh_sport = original_port;
481        }
482        else if (ip->ip_p == IPPROTO_ICMP)
483        {
484            u_short *sptr;
485            int accumulate;
486            struct in_addr original_address;
487            u_short original_id;
488
489            original_address = GetOriginalAddress(link);
490            original_id = GetOriginalPort(link);
491
492/* Adjust ICMP checksum */
493            sptr = (u_short *) &(ip->ip_src);
494            accumulate  = *sptr++;
495            accumulate += *sptr;
496            sptr = (u_short *) &original_address;
497            accumulate -= *sptr++;
498            accumulate -= *sptr;
499            accumulate += ic2->icmp_id;
500            accumulate -= original_id;
501            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
502
503/* Un-alias address in IP header */
504            DifferentialChecksum(&pip->ip_sum,
505                                 (u_short *) &original_address,
506                                 (u_short *) &pip->ip_dst,
507                                 2);
508            pip->ip_dst = original_address;
509
510/* Un-alias address of original IP packet and sequence number of
511   embedded ICMP datagram */
512            ip->ip_src = original_address;
513            ic2->icmp_id = original_id;
514        }
515        return(PKT_ALIAS_OK);
516    }
517    return(PKT_ALIAS_IGNORED);
518}
519
520
521static int
522IcmpAliasIn(struct ip *pip)
523{
524    int iresult;
525    struct icmp *ic;
526
527/* Return if proxy-only mode is enabled */
528    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
529        return PKT_ALIAS_OK;
530
531    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
532
533    iresult = PKT_ALIAS_IGNORED;
534    switch (ic->icmp_type)
535    {
536        case ICMP_ECHOREPLY:
537        case ICMP_TSTAMPREPLY:
538            if (ic->icmp_code == 0)
539            {
540                iresult = IcmpAliasIn1(pip);
541            }
542            break;
543        case ICMP_UNREACH:
544        case ICMP_SOURCEQUENCH:
545        case ICMP_TIMXCEED:
546        case ICMP_PARAMPROB:
547            iresult = IcmpAliasIn2(pip);
548            break;
549        case ICMP_ECHO:
550        case ICMP_TSTAMP:
551            iresult = IcmpAliasIn1(pip);
552            break;
553    }
554    return(iresult);
555}
556
557
558static int
559IcmpAliasOut1(struct ip *pip)
560{
561/*
562    Alias outgoing echo and timestamp requests.
563    De-alias outgoing echo and timestamp replies.
564*/
565    struct alias_link *link;
566    struct icmp *ic;
567
568    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
569
570/* Save overwritten data for when echo packet returns */
571    link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
572    if (link != NULL)
573    {
574        u_short alias_id;
575        int accumulate;
576
577        alias_id = GetAliasPort(link);
578
579/* Since data field is being modified, adjust ICMP checksum */
580        accumulate  = ic->icmp_id;
581        accumulate -= alias_id;
582        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
583
584/* Alias sequence number */
585        ic->icmp_id = alias_id;
586
587/* Change source address */
588        {
589            struct in_addr alias_address;
590
591            alias_address = GetAliasAddress(link);
592            DifferentialChecksum(&pip->ip_sum,
593                                 (u_short *) &alias_address,
594                                 (u_short *) &pip->ip_src,
595                                 2);
596            pip->ip_src = alias_address;
597        }
598
599        return(PKT_ALIAS_OK);
600    }
601    return(PKT_ALIAS_IGNORED);
602}
603
604
605static int
606IcmpAliasOut2(struct ip *pip)
607{
608/*
609    Alias outgoing ICMP error messages containing
610    IP header and first 64 bits of datagram.
611*/
612    struct ip *ip;
613    struct icmp *ic, *ic2;
614    struct udphdr *ud;
615    struct tcphdr *tc;
616    struct alias_link *link;
617
618    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
619    ip = &ic->icmp_ip;
620
621    ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
622    tc = (struct tcphdr *) ud;
623    ic2 = (struct icmp *) ud;
624
625    if (ip->ip_p == IPPROTO_UDP)
626        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
627                            ud->uh_dport, ud->uh_sport,
628                            IPPROTO_UDP, 0);
629    else if (ip->ip_p == IPPROTO_TCP)
630        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
631                            tc->th_dport, tc->th_sport,
632                            IPPROTO_TCP, 0);
633    else if (ip->ip_p == IPPROTO_ICMP) {
634        if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
635            link = FindIcmpOut(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
636        else
637            link = NULL;
638    } else
639        link = NULL;
640
641    if (link != NULL)
642    {
643        if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
644        {
645            u_short *sptr;
646            int accumulate;
647            struct in_addr alias_address;
648            u_short alias_port;
649
650            alias_address = GetAliasAddress(link);
651            alias_port = GetAliasPort(link);
652
653/* Adjust ICMP checksum */
654            sptr = (u_short *) &(ip->ip_dst);
655            accumulate  = *sptr++;
656            accumulate += *sptr;
657            sptr = (u_short *) &alias_address;
658            accumulate -= *sptr++;
659            accumulate -= *sptr;
660            accumulate += ud->uh_dport;
661            accumulate -= alias_port;
662            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
663
664/*
665 * Alias address in IP header if it comes from the host
666 * the original TCP/UDP packet was destined for.
667 */
668	    if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
669		DifferentialChecksum(&pip->ip_sum,
670				     (u_short *) &alias_address,
671				     (u_short *) &pip->ip_src,
672				     2);
673		pip->ip_src = alias_address;
674	    }
675
676/* Alias address and port number of original IP packet
677fragment contained in ICMP data section */
678            ip->ip_dst = alias_address;
679            ud->uh_dport = alias_port;
680        }
681        else if (ip->ip_p == IPPROTO_ICMP)
682        {
683            u_short *sptr;
684            int accumulate;
685            struct in_addr alias_address;
686            u_short alias_id;
687
688            alias_address = GetAliasAddress(link);
689            alias_id = GetAliasPort(link);
690
691/* Adjust ICMP checksum */
692            sptr = (u_short *) &(ip->ip_dst);
693            accumulate  = *sptr++;
694            accumulate += *sptr;
695            sptr = (u_short *) &alias_address;
696            accumulate -= *sptr++;
697            accumulate -= *sptr;
698            accumulate += ic2->icmp_id;
699            accumulate -= alias_id;
700            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
701
702/*
703 * Alias address in IP header if it comes from the host
704 * the original ICMP message was destined for.
705 */
706	    if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
707		DifferentialChecksum(&pip->ip_sum,
708				     (u_short *) &alias_address,
709				     (u_short *) &pip->ip_src,
710				     2);
711		pip->ip_src = alias_address;
712	    }
713
714/* Alias address of original IP packet and sequence number of
715   embedded ICMP datagram */
716            ip->ip_dst = alias_address;
717            ic2->icmp_id = alias_id;
718        }
719        return(PKT_ALIAS_OK);
720    }
721    return(PKT_ALIAS_IGNORED);
722}
723
724
725static int
726IcmpAliasOut(struct ip *pip)
727{
728    int iresult;
729    struct icmp *ic;
730
731/* Return if proxy-only mode is enabled */
732    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
733        return PKT_ALIAS_OK;
734
735    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
736
737    iresult = PKT_ALIAS_IGNORED;
738    switch (ic->icmp_type)
739    {
740        case ICMP_ECHO:
741        case ICMP_TSTAMP:
742            if (ic->icmp_code == 0)
743            {
744                iresult = IcmpAliasOut1(pip);
745            }
746            break;
747        case ICMP_UNREACH:
748        case ICMP_SOURCEQUENCH:
749        case ICMP_TIMXCEED:
750        case ICMP_PARAMPROB:
751            iresult = IcmpAliasOut2(pip);
752            break;
753        case ICMP_ECHOREPLY:
754        case ICMP_TSTAMPREPLY:
755            iresult = IcmpAliasOut1(pip);
756    }
757    return(iresult);
758}
759
760
761
762static int
763ProtoAliasIn(struct ip *pip)
764{
765/*
766  Handle incoming IP packets. The
767  only thing which is done in this case is to alias
768  the dest IP address of the packet to our inside
769  machine.
770*/
771    struct alias_link *link;
772
773/* Return if proxy-only mode is enabled */
774    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
775        return PKT_ALIAS_OK;
776
777    link = FindProtoIn(pip->ip_src, pip->ip_dst, pip->ip_p);
778    if (link != NULL)
779    {
780        struct in_addr original_address;
781
782        original_address = GetOriginalAddress(link);
783
784/* Restore original IP address */
785        DifferentialChecksum(&pip->ip_sum,
786                             (u_short *) &original_address,
787                             (u_short *) &pip->ip_dst,
788                             2);
789        pip->ip_dst = original_address;
790
791	return(PKT_ALIAS_OK);
792    }
793    return(PKT_ALIAS_IGNORED);
794}
795
796
797static int
798ProtoAliasOut(struct ip *pip)
799{
800/*
801  Handle outgoing IP packets. The
802  only thing which is done in this case is to alias
803  the source IP address of the packet.
804*/
805    struct alias_link *link;
806
807/* Return if proxy-only mode is enabled */
808    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
809        return PKT_ALIAS_OK;
810
811    link = FindProtoOut(pip->ip_src, pip->ip_dst, pip->ip_p);
812    if (link != NULL)
813    {
814        struct in_addr alias_address;
815
816        alias_address = GetAliasAddress(link);
817
818/* Change source address */
819        DifferentialChecksum(&pip->ip_sum,
820                             (u_short *) &alias_address,
821                             (u_short *) &pip->ip_src,
822                             2);
823        pip->ip_src = alias_address;
824
825        return(PKT_ALIAS_OK);
826    }
827    return(PKT_ALIAS_IGNORED);
828}
829
830
831static int
832UdpAliasIn(struct ip *pip)
833{
834    struct udphdr *ud;
835    struct alias_link *link;
836
837/* Return if proxy-only mode is enabled */
838    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
839        return PKT_ALIAS_OK;
840
841    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
842
843    link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
844                        ud->uh_sport, ud->uh_dport,
845                        IPPROTO_UDP, 1);
846    if (link != NULL)
847    {
848        struct in_addr alias_address;
849        struct in_addr original_address;
850        u_short alias_port;
851        int accumulate;
852        u_short *sptr;
853	int r = 0;
854
855        alias_address = GetAliasAddress(link);
856        original_address = GetOriginalAddress(link);
857        alias_port = ud->uh_dport;
858        ud->uh_dport = GetOriginalPort(link);
859
860/* Special processing for IP encoding protocols */
861	if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
862	    AliasHandleCUSeeMeIn(pip, original_address);
863/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
864	else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
865	      || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
866	    r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
867	else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
868	      || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
869	    r = AliasHandleUdpNbtNS(pip, link, &alias_address, &alias_port,
870				    &original_address, &ud->uh_dport);
871
872/* If UDP checksum is not zero, then adjust since destination port */
873/* is being unaliased and destination address is being altered.    */
874        if (ud->uh_sum != 0)
875        {
876            accumulate  = alias_port;
877            accumulate -= ud->uh_dport;
878            sptr = (u_short *) &alias_address;
879            accumulate += *sptr++;
880            accumulate += *sptr;
881            sptr = (u_short *) &original_address;
882            accumulate -= *sptr++;
883            accumulate -= *sptr;
884            ADJUST_CHECKSUM(accumulate, ud->uh_sum);
885        }
886
887/* Restore original IP address */
888        DifferentialChecksum(&pip->ip_sum,
889                             (u_short *) &original_address,
890                             (u_short *) &pip->ip_dst,
891                             2);
892        pip->ip_dst = original_address;
893
894	/*
895	 * If we cannot figure out the packet, ignore it.
896	 */
897	if (r < 0)
898	    return(PKT_ALIAS_IGNORED);
899	else
900	    return(PKT_ALIAS_OK);
901    }
902    return(PKT_ALIAS_IGNORED);
903}
904
905static int
906UdpAliasOut(struct ip *pip)
907{
908    struct udphdr *ud;
909    struct alias_link *link;
910
911/* Return if proxy-only mode is enabled */
912    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
913        return PKT_ALIAS_OK;
914
915    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
916
917    link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
918                         ud->uh_sport, ud->uh_dport,
919                         IPPROTO_UDP, 1);
920    if (link != NULL)
921    {
922        u_short alias_port;
923        struct in_addr alias_address;
924
925        alias_address = GetAliasAddress(link);
926        alias_port = GetAliasPort(link);
927
928/* Special processing for IP encoding protocols */
929	if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
930	    AliasHandleCUSeeMeOut(pip, link);
931/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
932	else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
933	      || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
934	    AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
935	else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
936	      || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
937	    AliasHandleUdpNbtNS(pip, link, &pip->ip_src, &ud->uh_sport,
938				&alias_address, &alias_port);
939
940/* If UDP checksum is not zero, adjust since source port is */
941/* being aliased and source address is being altered        */
942        if (ud->uh_sum != 0)
943        {
944            int accumulate;
945            u_short *sptr;
946
947            accumulate  = ud->uh_sport;
948            accumulate -= alias_port;
949            sptr = (u_short *) &(pip->ip_src);
950            accumulate += *sptr++;
951            accumulate += *sptr;
952            sptr = (u_short *) &alias_address;
953            accumulate -= *sptr++;
954            accumulate -= *sptr;
955            ADJUST_CHECKSUM(accumulate, ud->uh_sum);
956        }
957
958/* Put alias port in UDP header */
959        ud->uh_sport = alias_port;
960
961/* Change source address */
962        DifferentialChecksum(&pip->ip_sum,
963                             (u_short *) &alias_address,
964                             (u_short *) &pip->ip_src,
965                             2);
966        pip->ip_src = alias_address;
967
968        return(PKT_ALIAS_OK);
969    }
970    return(PKT_ALIAS_IGNORED);
971}
972
973
974
975static int
976TcpAliasIn(struct ip *pip)
977{
978    struct tcphdr *tc;
979    struct alias_link *link;
980
981    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
982
983    link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
984                        tc->th_sport, tc->th_dport,
985                        IPPROTO_TCP,
986                        !(packetAliasMode & PKT_ALIAS_PROXY_ONLY));
987    if (link != NULL)
988    {
989        struct in_addr alias_address;
990        struct in_addr original_address;
991        struct in_addr proxy_address;
992        u_short alias_port;
993        u_short proxy_port;
994        int accumulate;
995        u_short *sptr;
996
997/* Special processing for IP encoding protocols */
998        if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
999         || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
1000            AliasHandlePptpIn(pip, link);
1001
1002        alias_address = GetAliasAddress(link);
1003        original_address = GetOriginalAddress(link);
1004        proxy_address = GetProxyAddress(link);
1005        alias_port = tc->th_dport;
1006        tc->th_dport = GetOriginalPort(link);
1007        proxy_port = GetProxyPort(link);
1008
1009/* Adjust TCP checksum since destination port is being unaliased */
1010/* and destination port is being altered.                        */
1011        accumulate  = alias_port;
1012        accumulate -= tc->th_dport;
1013        sptr = (u_short *) &alias_address;
1014        accumulate += *sptr++;
1015        accumulate += *sptr;
1016        sptr = (u_short *) &original_address;
1017        accumulate -= *sptr++;
1018        accumulate -= *sptr;
1019
1020/* If this is a proxy, then modify the TCP source port and
1021   checksum accumulation */
1022        if (proxy_port != 0)
1023        {
1024            accumulate += tc->th_sport;
1025            tc->th_sport = proxy_port;
1026            accumulate -= tc->th_sport;
1027
1028            sptr = (u_short *) &pip->ip_src;
1029            accumulate += *sptr++;
1030            accumulate += *sptr;
1031            sptr = (u_short *) &proxy_address;
1032            accumulate -= *sptr++;
1033            accumulate -= *sptr;
1034        }
1035
1036/* See if ACK number needs to be modified */
1037        if (GetAckModified(link) == 1)
1038        {
1039            int delta;
1040
1041            delta = GetDeltaAckIn(pip, link);
1042            if (delta != 0)
1043            {
1044                sptr = (u_short *) &tc->th_ack;
1045                accumulate += *sptr++;
1046                accumulate += *sptr;
1047                tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1048                sptr = (u_short *) &tc->th_ack;
1049                accumulate -= *sptr++;
1050                accumulate -= *sptr;
1051            }
1052        }
1053
1054        ADJUST_CHECKSUM(accumulate, tc->th_sum);
1055
1056/* Restore original IP address */
1057        sptr = (u_short *) &pip->ip_dst;
1058        accumulate  = *sptr++;
1059        accumulate += *sptr;
1060        pip->ip_dst = original_address;
1061        sptr = (u_short *) &pip->ip_dst;
1062        accumulate -= *sptr++;
1063        accumulate -= *sptr;
1064
1065/* If this is a transparent proxy packet, then modify the source
1066   address */
1067        if (proxy_address.s_addr != 0)
1068        {
1069            sptr = (u_short *) &pip->ip_src;
1070            accumulate += *sptr++;
1071            accumulate += *sptr;
1072            pip->ip_src = proxy_address;
1073            sptr = (u_short *) &pip->ip_src;
1074            accumulate -= *sptr++;
1075            accumulate -= *sptr;
1076        }
1077
1078        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1079
1080/* Monitor TCP connection state */
1081        TcpMonitorIn(pip, link);
1082
1083        return(PKT_ALIAS_OK);
1084    }
1085    return(PKT_ALIAS_IGNORED);
1086}
1087
1088static int
1089TcpAliasOut(struct ip *pip, int maxpacketsize)
1090{
1091    int proxy_type;
1092    u_short dest_port;
1093    u_short proxy_server_port;
1094    struct in_addr dest_address;
1095    struct in_addr proxy_server_address;
1096    struct tcphdr *tc;
1097    struct alias_link *link;
1098
1099    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1100
1101    proxy_type = ProxyCheck(pip, &proxy_server_address, &proxy_server_port);
1102
1103    if (proxy_type == 0 && (packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1104        return PKT_ALIAS_OK;
1105
1106/* If this is a transparent proxy, save original destination,
1107   then alter the destination and adjust checksums */
1108    dest_port = tc->th_dport;
1109    dest_address = pip->ip_dst;
1110    if (proxy_type != 0)
1111    {
1112        int accumulate;
1113        u_short *sptr;
1114
1115        accumulate = tc->th_dport;
1116        tc->th_dport = proxy_server_port;
1117        accumulate -= tc->th_dport;
1118
1119        sptr = (u_short *) &(pip->ip_dst);
1120        accumulate += *sptr++;
1121        accumulate += *sptr;
1122        sptr = (u_short *) &proxy_server_address;
1123        accumulate -= *sptr++;
1124        accumulate -= *sptr;
1125
1126        ADJUST_CHECKSUM(accumulate, tc->th_sum);
1127
1128        sptr = (u_short *) &(pip->ip_dst);
1129        accumulate  = *sptr++;
1130        accumulate += *sptr;
1131        pip->ip_dst = proxy_server_address;
1132        sptr = (u_short *) &(pip->ip_dst);
1133        accumulate -= *sptr++;
1134        accumulate -= *sptr;
1135
1136        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1137    }
1138
1139    link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
1140                         tc->th_sport, tc->th_dport,
1141                         IPPROTO_TCP, 1);
1142    if (link !=NULL)
1143    {
1144        u_short alias_port;
1145        struct in_addr alias_address;
1146        int accumulate;
1147        u_short *sptr;
1148
1149/* Save original destination address, if this is a proxy packet.
1150   Also modify packet to include destination encoding. */
1151        if (proxy_type != 0)
1152        {
1153            SetProxyPort(link, dest_port);
1154            SetProxyAddress(link, dest_address);
1155            ProxyModify(link, pip, maxpacketsize, proxy_type);
1156        }
1157
1158/* Get alias address and port */
1159        alias_port = GetAliasPort(link);
1160        alias_address = GetAliasAddress(link);
1161
1162/* Monitor TCP connection state */
1163        TcpMonitorOut(pip, link);
1164
1165/* Special processing for IP encoding protocols */
1166        if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
1167         || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
1168            AliasHandleFtpOut(pip, link, maxpacketsize);
1169        else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
1170         || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
1171            AliasHandleIrcOut(pip, link, maxpacketsize);
1172        else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
1173         || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
1174         || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
1175         || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
1176            AliasHandleRtspOut(pip, link, maxpacketsize);
1177        else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
1178         || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
1179            AliasHandlePptpOut(pip, link);
1180
1181/* Adjust TCP checksum since source port is being aliased */
1182/* and source address is being altered                    */
1183        accumulate  = tc->th_sport;
1184        tc->th_sport = alias_port;
1185        accumulate -= tc->th_sport;
1186
1187        sptr = (u_short *) &(pip->ip_src);
1188        accumulate += *sptr++;
1189        accumulate += *sptr;
1190        sptr = (u_short *) &alias_address;
1191        accumulate -= *sptr++;
1192        accumulate -= *sptr;
1193
1194/* Modify sequence number if necessary */
1195        if (GetAckModified(link) == 1)
1196        {
1197            int delta;
1198
1199            delta = GetDeltaSeqOut(pip, link);
1200            if (delta != 0)
1201            {
1202                sptr = (u_short *) &tc->th_seq;
1203                accumulate += *sptr++;
1204                accumulate += *sptr;
1205                tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1206                sptr = (u_short *) &tc->th_seq;
1207                accumulate -= *sptr++;
1208                accumulate -= *sptr;
1209            }
1210        }
1211
1212        ADJUST_CHECKSUM(accumulate, tc->th_sum);
1213
1214/* Change source address */
1215        sptr = (u_short *) &(pip->ip_src);
1216        accumulate  = *sptr++;
1217        accumulate += *sptr;
1218        pip->ip_src = alias_address;
1219        sptr = (u_short *) &(pip->ip_src);
1220        accumulate -= *sptr++;
1221        accumulate -= *sptr;
1222
1223        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1224
1225        return(PKT_ALIAS_OK);
1226    }
1227    return(PKT_ALIAS_IGNORED);
1228}
1229
1230
1231
1232
1233/* Fragment Handling
1234
1235    FragmentIn()
1236    FragmentOut()
1237
1238The packet aliasing module has a limited ability for handling IP
1239fragments.  If the ICMP, TCP or UDP header is in the first fragment
1240received, then the ID number of the IP packet is saved, and other
1241fragments are identified according to their ID number and IP address
1242they were sent from.  Pointers to unresolved fragments can also be
1243saved and recalled when a header fragment is seen.
1244*/
1245
1246/* Local prototypes */
1247static int FragmentIn(struct ip *);
1248static int FragmentOut(struct ip *);
1249
1250
1251static int
1252FragmentIn(struct ip *pip)
1253{
1254    struct alias_link *link;
1255
1256    link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id);
1257    if (link != NULL)
1258    {
1259        struct in_addr original_address;
1260
1261        GetFragmentAddr(link, &original_address);
1262        DifferentialChecksum(&pip->ip_sum,
1263                             (u_short *) &original_address,
1264                             (u_short *) &pip->ip_dst,
1265                             2);
1266        pip->ip_dst = original_address;
1267
1268        return(PKT_ALIAS_OK);
1269    }
1270    return(PKT_ALIAS_UNRESOLVED_FRAGMENT);
1271}
1272
1273
1274static int
1275FragmentOut(struct ip *pip)
1276{
1277    struct in_addr alias_address;
1278
1279    alias_address = FindAliasAddress(pip->ip_src);
1280    DifferentialChecksum(&pip->ip_sum,
1281                         (u_short *) &alias_address,
1282                         (u_short *) &pip->ip_src,
1283                          2);
1284    pip->ip_src = alias_address;
1285
1286    return(PKT_ALIAS_OK);
1287}
1288
1289
1290
1291
1292
1293
1294/* Outside World Access
1295
1296        PacketAliasSaveFragment()
1297        PacketAliasGetFragment()
1298        PacketAliasFragmentIn()
1299        PacketAliasIn()
1300        PacketAliasOut()
1301        PacketUnaliasOut()
1302
1303(prototypes in alias.h)
1304*/
1305
1306
1307int
1308PacketAliasSaveFragment(char *ptr)
1309{
1310    int iresult;
1311    struct alias_link *link;
1312    struct ip *pip;
1313
1314    pip = (struct ip *) ptr;
1315    link = AddFragmentPtrLink(pip->ip_src, pip->ip_id);
1316    iresult = PKT_ALIAS_ERROR;
1317    if (link != NULL)
1318    {
1319        SetFragmentPtr(link, ptr);
1320        iresult = PKT_ALIAS_OK;
1321    }
1322    return(iresult);
1323}
1324
1325
1326char *
1327PacketAliasGetFragment(char *ptr)
1328{
1329    struct alias_link *link;
1330    char *fptr;
1331    struct ip *pip;
1332
1333    pip = (struct ip *) ptr;
1334    link = FindFragmentPtr(pip->ip_src, pip->ip_id);
1335    if (link != NULL)
1336    {
1337        GetFragmentPtr(link, &fptr);
1338        SetFragmentPtr(link, NULL);
1339        SetExpire(link, 0); /* Deletes link */
1340
1341        return(fptr);
1342    }
1343    else
1344    {
1345        return(NULL);
1346    }
1347}
1348
1349
1350void
1351PacketAliasFragmentIn(char *ptr,          /* Points to correctly de-aliased
1352                                             header fragment */
1353                      char *ptr_fragment  /* Points to fragment which must
1354                                             be de-aliased   */
1355                     )
1356{
1357    struct ip *pip;
1358    struct ip *fpip;
1359
1360    pip = (struct ip *) ptr;
1361    fpip = (struct ip *) ptr_fragment;
1362
1363    DifferentialChecksum(&fpip->ip_sum,
1364                         (u_short *) &pip->ip_dst,
1365                         (u_short *) &fpip->ip_dst,
1366                         2);
1367    fpip->ip_dst = pip->ip_dst;
1368}
1369
1370
1371int
1372PacketAliasIn(char *ptr, int maxpacketsize)
1373{
1374    struct in_addr alias_addr;
1375    struct ip *pip;
1376    int iresult;
1377
1378    if (packetAliasMode & PKT_ALIAS_REVERSE) {
1379        packetAliasMode &= ~PKT_ALIAS_REVERSE;
1380        iresult = PacketAliasOut(ptr, maxpacketsize);
1381        packetAliasMode |= PKT_ALIAS_REVERSE;
1382        return iresult;
1383    }
1384
1385    HouseKeeping();
1386    ClearCheckNewLink();
1387    pip = (struct ip *) ptr;
1388    alias_addr = pip->ip_dst;
1389
1390    /* Defense against mangled packets */
1391    if (ntohs(pip->ip_len) > maxpacketsize
1392     || (pip->ip_hl<<2) > maxpacketsize)
1393        return PKT_ALIAS_IGNORED;
1394
1395    iresult = PKT_ALIAS_IGNORED;
1396    if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 )
1397    {
1398        switch (pip->ip_p)
1399        {
1400            case IPPROTO_ICMP:
1401                iresult = IcmpAliasIn(pip);
1402                break;
1403            case IPPROTO_UDP:
1404                iresult = UdpAliasIn(pip);
1405                break;
1406            case IPPROTO_TCP:
1407                iresult = TcpAliasIn(pip);
1408                break;
1409            case IPPROTO_GRE:
1410		if (packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
1411		    AliasHandlePptpGreIn(pip) == 0)
1412		    iresult = PKT_ALIAS_OK;
1413		else
1414		    iresult = ProtoAliasIn(pip);
1415		break;
1416	    default:
1417		iresult = ProtoAliasIn(pip);
1418                break;
1419        }
1420
1421        if (ntohs(pip->ip_off) & IP_MF)
1422        {
1423            struct alias_link *link;
1424
1425            link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id);
1426            if (link != NULL)
1427            {
1428                iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1429                SetFragmentAddr(link, pip->ip_dst);
1430            }
1431            else
1432            {
1433                iresult = PKT_ALIAS_ERROR;
1434            }
1435        }
1436    }
1437    else
1438    {
1439        iresult = FragmentIn(pip);
1440    }
1441
1442    return(iresult);
1443}
1444
1445
1446
1447/* Unregistered address ranges */
1448
1449/* 10.0.0.0   ->   10.255.255.255 */
1450#define UNREG_ADDR_A_LOWER 0x0a000000
1451#define UNREG_ADDR_A_UPPER 0x0affffff
1452
1453/* 172.16.0.0  ->  172.31.255.255 */
1454#define UNREG_ADDR_B_LOWER 0xac100000
1455#define UNREG_ADDR_B_UPPER 0xac1fffff
1456
1457/* 192.168.0.0 -> 192.168.255.255 */
1458#define UNREG_ADDR_C_LOWER 0xc0a80000
1459#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1460
1461int
1462PacketAliasOut(char *ptr,           /* valid IP packet */
1463               int  maxpacketsize   /* How much the packet data may grow
1464                                       (FTP and IRC inline changes) */
1465              )
1466{
1467    int iresult;
1468    struct in_addr addr_save;
1469    struct ip *pip;
1470
1471    if (packetAliasMode & PKT_ALIAS_REVERSE) {
1472        packetAliasMode &= ~PKT_ALIAS_REVERSE;
1473        iresult = PacketAliasIn(ptr, maxpacketsize);
1474        packetAliasMode |= PKT_ALIAS_REVERSE;
1475        return iresult;
1476    }
1477
1478    HouseKeeping();
1479    ClearCheckNewLink();
1480    pip = (struct ip *) ptr;
1481
1482    /* Defense against mangled packets */
1483    if (ntohs(pip->ip_len) > maxpacketsize
1484     || (pip->ip_hl<<2) > maxpacketsize)
1485        return PKT_ALIAS_IGNORED;
1486
1487    addr_save = GetDefaultAliasAddress();
1488    if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY)
1489    {
1490        in_addr_t addr;
1491        int iclass;
1492
1493        iclass = 0;
1494        addr = ntohl(pip->ip_src.s_addr);
1495        if      (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1496            iclass = 3;
1497        else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1498            iclass = 2;
1499        else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1500            iclass = 1;
1501
1502        if (iclass == 0)
1503        {
1504            SetDefaultAliasAddress(pip->ip_src);
1505        }
1506    }
1507
1508    iresult = PKT_ALIAS_IGNORED;
1509    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0)
1510    {
1511        switch (pip->ip_p)
1512        {
1513            case IPPROTO_ICMP:
1514                iresult = IcmpAliasOut(pip);
1515                break;
1516            case IPPROTO_UDP:
1517                iresult = UdpAliasOut(pip);
1518                break;
1519            case IPPROTO_TCP:
1520                iresult = TcpAliasOut(pip, maxpacketsize);
1521                break;
1522	    case IPPROTO_GRE:
1523		if (AliasHandlePptpGreOut(pip) == 0)
1524		    iresult = PKT_ALIAS_OK;
1525		else
1526		    iresult = ProtoAliasOut(pip);
1527		break;
1528	    default:
1529		iresult = ProtoAliasOut(pip);
1530                break;
1531        }
1532    }
1533    else
1534    {
1535        iresult = FragmentOut(pip);
1536    }
1537
1538    SetDefaultAliasAddress(addr_save);
1539    return(iresult);
1540}
1541
1542int
1543PacketUnaliasOut(char *ptr,           /* valid IP packet */
1544                 int  maxpacketsize   /* for error checking */
1545                )
1546{
1547    struct ip		*pip;
1548    struct icmp 	*ic;
1549    struct udphdr	*ud;
1550    struct tcphdr 	*tc;
1551    struct alias_link 	*link;
1552    int 		iresult = PKT_ALIAS_IGNORED;
1553
1554    pip = (struct ip *) ptr;
1555
1556    /* Defense against mangled packets */
1557    if (ntohs(pip->ip_len) > maxpacketsize
1558     || (pip->ip_hl<<2) > maxpacketsize)
1559        return(iresult);
1560
1561    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
1562    tc = (struct tcphdr *) ud;
1563    ic = (struct icmp *) ud;
1564
1565    /* Find a link */
1566    if (pip->ip_p == IPPROTO_UDP)
1567        link = FindUdpTcpIn(pip->ip_dst, pip->ip_src,
1568                            ud->uh_dport, ud->uh_sport,
1569                            IPPROTO_UDP, 0);
1570    else if (pip->ip_p == IPPROTO_TCP)
1571        link = FindUdpTcpIn(pip->ip_dst, pip->ip_src,
1572                            tc->th_dport, tc->th_sport,
1573                            IPPROTO_TCP, 0);
1574    else if (pip->ip_p == IPPROTO_ICMP)
1575        link = FindIcmpIn(pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1576    else
1577        link = NULL;
1578
1579    /* Change it from an aliased packet to an unaliased packet */
1580    if (link != NULL)
1581    {
1582        if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP)
1583        {
1584            u_short        *sptr;
1585            int 	   accumulate;
1586            struct in_addr original_address;
1587            u_short        original_port;
1588
1589            original_address = GetOriginalAddress(link);
1590            original_port = GetOriginalPort(link);
1591
1592            /* Adjust TCP/UDP checksum */
1593            sptr = (u_short *) &(pip->ip_src);
1594            accumulate  = *sptr++;
1595            accumulate += *sptr;
1596            sptr = (u_short *) &original_address;
1597            accumulate -= *sptr++;
1598            accumulate -= *sptr;
1599
1600            if (pip->ip_p == IPPROTO_UDP) {
1601                accumulate += ud->uh_sport;
1602                accumulate -= original_port;
1603                ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1604	    } else {
1605                accumulate += tc->th_sport;
1606                accumulate -= original_port;
1607                ADJUST_CHECKSUM(accumulate, tc->th_sum);
1608	    }
1609
1610            /* Adjust IP checksum */
1611            DifferentialChecksum(&pip->ip_sum,
1612                                 (u_short *) &original_address,
1613                                 (u_short *) &pip->ip_src,
1614                                 2);
1615
1616            /* Un-alias source address and port number */
1617            pip->ip_src = original_address;
1618            if (pip->ip_p == IPPROTO_UDP)
1619                ud->uh_sport = original_port;
1620	    else
1621                tc->th_sport = original_port;
1622
1623	    iresult = PKT_ALIAS_OK;
1624
1625        } else if (pip->ip_p == IPPROTO_ICMP) {
1626
1627            u_short        *sptr;
1628            int            accumulate;
1629            struct in_addr original_address;
1630            u_short        original_id;
1631
1632            original_address = GetOriginalAddress(link);
1633            original_id = GetOriginalPort(link);
1634
1635            /* Adjust ICMP checksum */
1636            sptr = (u_short *) &(pip->ip_src);
1637            accumulate  = *sptr++;
1638            accumulate += *sptr;
1639            sptr = (u_short *) &original_address;
1640            accumulate -= *sptr++;
1641            accumulate -= *sptr;
1642            accumulate += ic->icmp_id;
1643            accumulate -= original_id;
1644            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1645
1646            /* Adjust IP checksum */
1647            DifferentialChecksum(&pip->ip_sum,
1648                                 (u_short *) &original_address,
1649                                 (u_short *) &pip->ip_src,
1650                                 2);
1651
1652            /* Un-alias source address and port number */
1653            pip->ip_src = original_address;
1654            ic->icmp_id = original_id;
1655
1656	    iresult = PKT_ALIAS_OK;
1657        }
1658    }
1659    return(iresult);
1660
1661}
1662