]> git.saurik.com Git - apple/network_cmds.git/blobdiff - alias/alias.c
network_cmds-328.tar.gz
[apple/network_cmds.git] / alias / alias.c
index 10e0ccc3164380720b65de3fd15180c8e5c5a696..668dbe1c9df846ca3f6676b85b9c02a7c25a0157 100644 (file)
@@ -1,4 +1,53 @@
-/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
+/*
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Based upon:
+ * $FreeBSD: src/lib/libalias/alias.c,v 1.16.2.7 2001/08/21 03:50:25 brian Exp $
+ */
+
 /*
     Alias.c provides supervisory control for the functions of the
     packet aliasing software.  It consists of routines to monitor
     function calls, so other segments of the program need not know
     about the underlying data structures.  Alias_ftp.c contains
     special code for modifying the ftp PORT command used to establish
-    data connections, while alias_irc.c do the same for IRC
+    data connections, while alias_irc.c does the same for IRC
     DCC. Alias_util.c contains a few utility routines.
 
-    This software is placed into the public domain with no restrictions
-    on its distribution.
-
     Version 1.0 August, 1996  (cjm)
 
     Version 1.1 August 20, 1996  (cjm)
     Version 2.3 Dec 1998 (dillon)
        - Major bounds checking additions, see FreeBSD/CVS
 
-    See HISTORY file for additional revisions.
+    Version 3.1 May, 2000 (salander) 
+       - Added hooks to handle PPTP.
 
-*/
+    Version 3.2 July, 2000 (salander and satoh)
+       - Added PacketUnaliasOut routine.
+       - Added hooks to handle RTSP/RTP.
 
-#include <stdio.h>
-#include <unistd.h>
+    See HISTORY file for additional revisions.
+*/
 
-#include <sys/param.h>
 #include <sys/types.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 
-#ifndef IPPROTO_GRE
-#define IPPROTO_GRE 47
-#endif
+#include <stdio.h>
 
 #include "alias_local.h"
 #include "alias.h"
 #define IRC_CONTROL_PORT_NUMBER_1 6667
 #define IRC_CONTROL_PORT_NUMBER_2 6668
 #define CUSEEME_PORT_NUMBER 7648
+#define RTSP_CONTROL_PORT_NUMBER_1 554
+#define RTSP_CONTROL_PORT_NUMBER_2 7070
+#define PPTP_CONTROL_PORT_NUMBER 1723
 
 
 
     TcpMonitorIn()  -- These routines monitor TCP connections, and
     TcpMonitorOut()    delete a link when a connection is closed.
 
-These routines look for SYN, ACK and RST flags to determine when TCP
+       DoMSSClamp()    -- Clamps the MSS of the given TCP header to the
+                       value in packetAliasMSS.
+
+These routines look for SYN, FIN and RST flags to determine when TCP
 connections open and close.  When a TCP connection closes, the data
 structure containing packet aliasing information is deleted after
 a timeout period.
@@ -127,6 +179,72 @@ static void TcpMonitorIn(struct ip *, struct alias_link *);
 static void TcpMonitorOut(struct ip *, struct alias_link *);
 
 
+static u_short packetAliasMSS;
+
+void PacketAliasClampMSS(u_short mss)
+{
+    packetAliasMSS = mss;
+}
+
+static void DoMSSClamp(struct tcphdr *tc)
+{
+    u_char *option    = (u_char *) tc + sizeof(*tc);
+    u_char *optionEnd = option + ((tc->th_off << 2) - sizeof(*tc));
+
+#define TEST_5618045 0
+#if TEST_5618045
+       if ((ntohs(tc->th_dport) == 8080 || ntohs(tc->th_sport) == 8080) && tc->th_off > 5) {
+               option[0] = 0xF4;
+               option[1] = 0;
+       }
+#endif
+
+    while (optionEnd > option)
+    {
+        /* Bounds checking to avoid infinite loops */
+        if (option[0] == TCPOPT_EOL)
+            break;
+        
+        if (option[0] == TCPOPT_NOP) {
+            ++option;
+            continue;
+        } else {
+            if (optionEnd - option < 2)
+                break;
+            if (option[1] < 2 || option + option[1] >= optionEnd)
+                break;
+       }
+
+        switch (option[0])
+        {
+            case TCPOPT_MAXSEG:
+                if (option[1] == 4)
+                {
+                    u_short *mssPtr = (u_short *) option + 1;
+                    u_short mssVal  = ntohs(*mssPtr);
+
+                    if (packetAliasMSS < mssVal)
+                    {
+                        int accumulate = mssVal;
+                        int accnetorder = 0 ;
+                        
+                        accumulate -= packetAliasMSS;
+                        *mssPtr = htons(packetAliasMSS);
+                        accnetorder = htons(accumulate);
+                        ADJUST_CHECKSUM(accnetorder, tc->th_sum);
+                    }
+
+                    option = optionEnd;
+                }
+                break;
+
+            default:
+                option += option[1];
+                break;
+        }
+    }
+}
+
 static void
 TcpMonitorIn(struct ip *pip, struct alias_link *link)
 {
@@ -137,12 +255,18 @@ TcpMonitorIn(struct ip *pip, struct alias_link *link)
     switch (GetStateIn(link))
     {
         case ALIAS_TCP_STATE_NOT_CONNECTED:
-            if (tc->th_flags & TH_SYN)
+            if (tc->th_flags & TH_RST)
+                SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
+            else if (tc->th_flags & TH_SYN)
+            {
                 SetStateIn(link, ALIAS_TCP_STATE_CONNECTED);
+
+                if (packetAliasMSS)
+                    DoMSSClamp(tc);
+            }
             break;
         case ALIAS_TCP_STATE_CONNECTED:
-            if (tc->th_flags & TH_FIN
-                || tc->th_flags & TH_RST)
+            if (tc->th_flags & (TH_FIN | TH_RST))
                 SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
             break;
     }
@@ -158,12 +282,18 @@ TcpMonitorOut(struct ip *pip, struct alias_link *link)
     switch (GetStateOut(link))
     {
         case ALIAS_TCP_STATE_NOT_CONNECTED:
-            if (tc->th_flags & TH_SYN)
+            if (tc->th_flags & TH_RST)
+                SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
+            else if (tc->th_flags & TH_SYN)
+            {
                 SetStateOut(link, ALIAS_TCP_STATE_CONNECTED);
+
+                if (packetAliasMSS)
+                    DoMSSClamp(tc);
+            }
             break;
         case ALIAS_TCP_STATE_CONNECTED:
-            if (tc->th_flags & TH_FIN
-                || tc->th_flags & TH_RST)
+            if (tc->th_flags & (TH_FIN | TH_RST))
                 SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
             break;
     }
@@ -175,8 +305,9 @@ TcpMonitorOut(struct ip *pip, struct alias_link *link)
 
 /* Protocol Specific Packet Aliasing Routines 
 
-    IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3()
-    IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3()
+    IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
+    IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
+    ProtoAliasIn(), ProtoAliasOut()
     UdpAliasIn(), UdpAliasOut()
     TcpAliasIn(), TcpAliasOut()
 
@@ -191,7 +322,7 @@ address of the outgoing packet and then correctly put it back for
 any incoming packets.  For TCP and UDP, ports are also re-mapped.
 
 For ICMP echo/timestamp requests and replies, the following scheme
-is used: the id number is replaced by an alias for the outgoing
+is used: the ID number is replaced by an alias for the outgoing
 packet.
 
 ICMP error messages are handled by looking at the IP fragment
@@ -200,7 +331,7 @@ in the data section of the message.
 For TCP and UDP protocols, a port number is chosen for an outgoing
 packet, and then incoming packets are identified by IP address and
 port numbers.  For TCP packets, there is additional logic in the event
-that sequence and ack numbers have been altered (as is the case for
+that sequence and ACK numbers have been altered (as in the case for
 FTP data port commands).
 
 The port numbers used by the packet aliasing module are not true
@@ -215,14 +346,15 @@ the gateway machine or other machines on a local area network.
 /* Local prototypes */
 static int IcmpAliasIn1(struct ip *);
 static int IcmpAliasIn2(struct ip *);
-static int IcmpAliasIn3(struct ip *);
 static int IcmpAliasIn (struct ip *);
 
 static int IcmpAliasOut1(struct ip *);
 static int IcmpAliasOut2(struct ip *);
-static int IcmpAliasOut3(struct ip *);
 static int IcmpAliasOut (struct ip *);
 
+static int ProtoAliasIn(struct ip *);
+static int ProtoAliasOut(struct ip *);
+
 static int UdpAliasOut(struct ip *);
 static int UdpAliasIn (struct ip *);
 
@@ -234,7 +366,8 @@ static int
 IcmpAliasIn1(struct ip *pip)
 {
 /*
-    De-alias incoming echo and timestamp replies
+    De-alias incoming echo and timestamp replies.
+    Alias incoming echo and timestamp requests.
 */
     struct alias_link *link;
     struct icmp *ic;
@@ -242,7 +375,7 @@ IcmpAliasIn1(struct ip *pip)
     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
 
 /* Get source address from ICMP data field and restore original data */
-    link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id);
+    link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
     if (link != NULL)
     {
         u_short original_id;
@@ -253,7 +386,7 @@ IcmpAliasIn1(struct ip *pip)
 /* Adjust ICMP checksum */
         accumulate  = ic->icmp_id;
         accumulate -= original_id;
-        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
 /* Put original sequence number back in */
         ic->icmp_id = original_id;
@@ -289,7 +422,7 @@ IcmpAliasIn2(struct ip *pip)
     struct alias_link *link;
 
     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
-    ip = (struct ip *) ic->icmp_data;
+    ip = &ic->icmp_ip;
 
     ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
     tc = (struct tcphdr *) ud;
@@ -298,15 +431,15 @@ IcmpAliasIn2(struct ip *pip)
     if (ip->ip_p == IPPROTO_UDP)
         link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
                             ud->uh_dport, ud->uh_sport,
-                            IPPROTO_UDP);
+                            IPPROTO_UDP, 0);
     else if (ip->ip_p == IPPROTO_TCP)
         link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
                             tc->th_dport, tc->th_sport,
-                            IPPROTO_TCP);
+                            IPPROTO_TCP, 0);
     else if (ip->ip_p == IPPROTO_ICMP) {
         if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
-            link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id);
-         else
+            link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
+        else
             link = NULL;
     } else
         link = NULL;
@@ -332,7 +465,7 @@ IcmpAliasIn2(struct ip *pip)
             accumulate -= *sptr;
             accumulate += ud->uh_sport;
             accumulate -= original_port;
-            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
 /* Un-alias address in IP header */
             DifferentialChecksum(&pip->ip_sum,
@@ -346,7 +479,7 @@ fragment contained in ICMP data section */
             ip->ip_src = original_address;
             ud->uh_sport = original_port; 
         }
-        else if (pip->ip_p == IPPROTO_ICMP)
+        else if (ip->ip_p == IPPROTO_ICMP)
         {
             u_short *sptr;
             int accumulate;
@@ -365,7 +498,7 @@ fragment contained in ICMP data section */
             accumulate -= *sptr;
             accumulate += ic2->icmp_id;
             accumulate -= original_id;
-            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
 /* Un-alias address in IP header */
             DifferentialChecksum(&pip->ip_sum,
@@ -374,8 +507,8 @@ fragment contained in ICMP data section */
                                  2);
             pip->ip_dst = original_address;
 
-/* Un-alias address of original IP packet and seqence number of 
-   embedded icmp datagram */
+/* Un-alias address of original IP packet and sequence number of 
+   embedded ICMP datagram */
             ip->ip_src = original_address;
             ic2->icmp_id = original_id;
         }
@@ -384,21 +517,6 @@ fragment contained in ICMP data section */
     return(PKT_ALIAS_IGNORED);
 }
 
-static int
-IcmpAliasIn3(struct ip *pip)
-{
-    struct in_addr original_address;
-
-    original_address = FindOriginalAddress(pip->ip_dst);
-    DifferentialChecksum(&pip->ip_sum,
-                         (u_short *) &original_address,
-                         (u_short *) &pip->ip_dst,
-                         2);
-    pip->ip_dst = original_address;
-
-    return PKT_ALIAS_OK;
-}
-
 
 static int
 IcmpAliasIn(struct ip *pip)
@@ -430,7 +548,7 @@ IcmpAliasIn(struct ip *pip)
             break;
         case ICMP_ECHO:
         case ICMP_TSTAMP:
-            iresult = IcmpAliasIn3(pip);
+            iresult = IcmpAliasIn1(pip);
             break;
     }
     return(iresult);
@@ -441,7 +559,8 @@ static int
 IcmpAliasOut1(struct ip *pip)
 {
 /*
-    Alias ICMP echo and timestamp packets
+    Alias outgoing echo and timestamp requests.
+    De-alias outgoing echo and timestamp replies.
 */
     struct alias_link *link;
     struct icmp *ic;
@@ -449,7 +568,7 @@ IcmpAliasOut1(struct ip *pip)
     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
 
 /* Save overwritten data for when echo packet returns */
-    link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id);
+    link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
     if (link != NULL)
     {
         u_short alias_id;
@@ -460,7 +579,7 @@ IcmpAliasOut1(struct ip *pip)
 /* Since data field is being modified, adjust ICMP checksum */
         accumulate  = ic->icmp_id;
         accumulate -= alias_id;
-        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
+        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
 /* Alias sequence number */
         ic->icmp_id = alias_id;
@@ -490,51 +609,116 @@ IcmpAliasOut2(struct ip *pip)
     Alias outgoing ICMP error messages containing
     IP header and first 64 bits of datagram.
 */
-    struct in_addr alias_addr;
     struct ip *ip;
-    struct icmp *ic;
+    struct icmp *ic, *ic2;
+    struct udphdr *ud;
+    struct tcphdr *tc;
+    struct alias_link *link;
 
     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
-    ip = (struct ip *) ic->icmp_data;
+    ip = &ic->icmp_ip;
 
-    alias_addr = FindAliasAddress(ip->ip_src);
-
-/* Alias destination address in IP fragment */
-    DifferentialChecksum(&ic->icmp_cksum,
-                         (u_short *) &alias_addr,
-                         (u_short *) &ip->ip_dst,
-                         2);
-    ip->ip_dst = alias_addr;
+    ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
+    tc = (struct tcphdr *) ud;
+    ic2 = (struct icmp *) ud;
 
-/* alias source address in IP header */
-    DifferentialChecksum(&pip->ip_sum,
-                         (u_short *) &alias_addr,
-                         (u_short *) &pip->ip_src,
-                         2);
-    pip->ip_src = alias_addr;
+    if (ip->ip_p == IPPROTO_UDP)
+        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
+                            ud->uh_dport, ud->uh_sport,
+                            IPPROTO_UDP, 0);
+    else if (ip->ip_p == IPPROTO_TCP)
+        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
+                            tc->th_dport, tc->th_sport,
+                            IPPROTO_TCP, 0);
+    else if (ip->ip_p == IPPROTO_ICMP) {
+        if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
+            link = FindIcmpOut(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
+        else
+            link = NULL;
+    } else
+        link = NULL;
 
-    return PKT_ALIAS_OK;
-}
+    if (link != NULL)
+    {
+        if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
+        {
+            u_short *sptr;
+            int accumulate;
+            struct in_addr alias_address;
+            u_short alias_port;
 
+            alias_address = GetAliasAddress(link);
+            alias_port = GetAliasPort(link);
+    
+/* Adjust ICMP checksum */
+            sptr = (u_short *) &(ip->ip_dst);
+            accumulate  = *sptr++;
+            accumulate += *sptr;
+            sptr = (u_short *) &alias_address;
+            accumulate -= *sptr++;
+            accumulate -= *sptr;
+            accumulate += ud->uh_dport;
+            accumulate -= alias_port;
+            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
-static int
-IcmpAliasOut3(struct ip *pip)
-{
 /*
-  Handle outgoing echo and timestamp replies.  The
-  only thing which is done in this case is to alias
-  the source IP address of the packet.
-*/
-    struct in_addr alias_addr;
+ * Alias address in IP header if it comes from the host
+ * the original TCP/UDP packet was destined for.
+ */
+           if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
+               DifferentialChecksum(&pip->ip_sum,
+                                    (u_short *) &alias_address,
+                                    (u_short *) &pip->ip_src,
+                                    2);
+               pip->ip_src = alias_address;
+           }
+
+/* Alias address and port number of original IP packet
+fragment contained in ICMP data section */
+            ip->ip_dst = alias_address;
+            ud->uh_dport = alias_port; 
+        }
+        else if (ip->ip_p == IPPROTO_ICMP)
+        {
+            u_short *sptr;
+            int accumulate;
+            struct in_addr alias_address;
+            u_short alias_id;
 
-    alias_addr = FindAliasAddress(pip->ip_src);
-    DifferentialChecksum(&pip->ip_sum,
-                         (u_short *) &alias_addr,
-                         (u_short *) &pip->ip_src,
-                         2);
-    pip->ip_src = alias_addr;
+            alias_address = GetAliasAddress(link);
+            alias_id = GetAliasPort(link);
+
+/* Adjust ICMP checksum */
+            sptr = (u_short *) &(ip->ip_dst);
+            accumulate  = *sptr++;
+            accumulate += *sptr;
+            sptr = (u_short *) &alias_address;
+            accumulate -= *sptr++;
+            accumulate -= *sptr;
+            accumulate += ic2->icmp_id;
+            accumulate -= alias_id;
+            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
 
-    return PKT_ALIAS_OK;
+/*
+ * Alias address in IP header if it comes from the host
+ * the original ICMP message was destined for.
+ */
+           if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
+               DifferentialChecksum(&pip->ip_sum,
+                                    (u_short *) &alias_address,
+                                    (u_short *) &pip->ip_src,
+                                    2);
+               pip->ip_src = alias_address;
+           }
+
+/* Alias address of original IP packet and sequence number of 
+   embedded ICMP datagram */
+            ip->ip_dst = alias_address;
+            ic2->icmp_id = alias_id;
+        }
+        return(PKT_ALIAS_OK);
+    }
+    return(PKT_ALIAS_IGNORED);
 }
 
 
@@ -568,7 +752,7 @@ IcmpAliasOut(struct ip *pip)
             break;
         case ICMP_ECHOREPLY:
         case ICMP_TSTAMPREPLY:
-            iresult = IcmpAliasOut3(pip);
+            iresult = IcmpAliasOut1(pip);
     }
     return(iresult);
 }
@@ -576,58 +760,72 @@ IcmpAliasOut(struct ip *pip)
 
 
 static int
-PptpAliasIn(struct ip *pip)
+ProtoAliasIn(struct ip *pip)
 {
 /*
-  Handle incoming PPTP packets. The
+  Handle incoming IP packets. The
   only thing which is done in this case is to alias
   the dest IP address of the packet to our inside
   machine.
 */
-    struct in_addr alias_addr;
+    struct alias_link *link;
 
-    if (!GetPptpAlias (&alias_addr))
-       return PKT_ALIAS_IGNORED;
+/* Return if proxy-only mode is enabled */
+    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
+        return PKT_ALIAS_OK;
 
-    if (pip->ip_src.s_addr != alias_addr.s_addr) {
+    link = FindProtoIn(pip->ip_src, pip->ip_dst, pip->ip_p);
+    if (link != NULL)
+    {
+        struct in_addr original_address;
 
-           DifferentialChecksum(&pip->ip_sum,
-                                (u_short *) &alias_addr,
-                                (u_short *) &pip->ip_dst,
-                                2);
-           pip->ip_dst = alias_addr;
-    }
+        original_address = GetOriginalAddress(link);
+
+/* Restore original IP address */
+        DifferentialChecksum(&pip->ip_sum,
+                             (u_short *) &original_address,
+                             (u_short *) &pip->ip_dst,
+                             2);
+        pip->ip_dst = original_address;
 
-    return PKT_ALIAS_OK;
+       return(PKT_ALIAS_OK);
+    }
+    return(PKT_ALIAS_IGNORED);
 }
 
 
 static int
-PptpAliasOut(struct ip *pip)
+ProtoAliasOut(struct ip *pip)
 {
 /*
-  Handle outgoing PPTP packets. The
+  Handle outgoing IP packets. The
   only thing which is done in this case is to alias
   the source IP address of the packet.
 */
-    struct in_addr alias_addr;
+    struct alias_link *link;
 
-    if (!GetPptpAlias (&alias_addr))
-       return PKT_ALIAS_IGNORED;
+/* Return if proxy-only mode is enabled */
+    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
+        return PKT_ALIAS_OK;
 
-    if (pip->ip_src.s_addr == alias_addr.s_addr) {
+    link = FindProtoOut(pip->ip_src, pip->ip_dst, pip->ip_p);
+    if (link != NULL)
+    {
+        struct in_addr alias_address;
 
-           alias_addr = FindAliasAddress(pip->ip_src);
-           DifferentialChecksum(&pip->ip_sum,
-                                (u_short *) &alias_addr,
-                                (u_short *) &pip->ip_src,
-                                2);
-           pip->ip_src = alias_addr;
-    }
+        alias_address = GetAliasAddress(link);
 
-    return PKT_ALIAS_OK;
-}
+/* Change source address */
+        DifferentialChecksum(&pip->ip_sum,
+                             (u_short *) &alias_address,
+                             (u_short *) &pip->ip_src,
+                             2);
+        pip->ip_src = alias_address;
 
+        return(PKT_ALIAS_OK);
+    }
+    return(PKT_ALIAS_IGNORED);
+}
 
 
 static int
@@ -644,7 +842,7 @@ UdpAliasIn(struct ip *pip)
 
     link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
                         ud->uh_sport, ud->uh_dport,
-                        IPPROTO_UDP);
+                        IPPROTO_UDP, 1);
     if (link != NULL)
     {
         struct in_addr alias_address;
@@ -659,26 +857,20 @@ UdpAliasIn(struct ip *pip)
         alias_port = ud->uh_dport;
         ud->uh_dport = GetOriginalPort(link);
 
+/* Special processing for IP encoding protocols */
+       if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
+           AliasHandleCUSeeMeIn(pip, original_address);
 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
-               if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
-         || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
-               {
-            r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
-               } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
-         || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
-               {
-            r = AliasHandleUdpNbtNS(pip, link, 
-                                                               &alias_address,
-                                                               &alias_port,
-                                                               &original_address, 
-                                                               &ud->uh_dport );
-               }
-
-        if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
-            AliasHandleCUSeeMeIn(pip, original_address);
+       else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
+             || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
+           r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
+       else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
+             || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
+           r = AliasHandleUdpNbtNS(pip, link, &alias_address, &alias_port,
+                                   &original_address, &ud->uh_dport);
 
 /* If UDP checksum is not zero, then adjust since destination port */
-/* is being unaliased and destination port is being altered.       */
+/* is being unaliased and destination address is being altered.    */
         if (ud->uh_sum != 0)
         {
             accumulate  = alias_port;
@@ -689,7 +881,7 @@ UdpAliasIn(struct ip *pip)
             sptr = (u_short *) &original_address;
             accumulate -= *sptr++;
             accumulate -= *sptr;
-            ADJUST_CHECKSUM(accumulate, ud->uh_sum)
+            ADJUST_CHECKSUM(accumulate, ud->uh_sum);
         }
 
 /* Restore original IP address */
@@ -724,7 +916,7 @@ UdpAliasOut(struct ip *pip)
 
     link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
                          ud->uh_sport, ud->uh_dport,
-                         IPPROTO_UDP);
+                         IPPROTO_UDP, 1);
     if (link != NULL)
     {
         u_short alias_port;
@@ -733,23 +925,17 @@ UdpAliasOut(struct ip *pip)
         alias_address = GetAliasAddress(link);
         alias_port = GetAliasPort(link);
 
-        if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
-            AliasHandleCUSeeMeOut(pip, link);
-
+/* Special processing for IP encoding protocols */
+       if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
+           AliasHandleCUSeeMeOut(pip, link);
 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
-               if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
-         || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
-               {
-            AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
-               } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
-         || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
-               {
-            AliasHandleUdpNbtNS(pip, link,
-                                                               &pip->ip_src,
-                                                               &ud->uh_sport,
-                                                           &alias_address,
-                                                               &alias_port); 
-               }
+       else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
+             || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
+           AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
+       else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
+             || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
+           AliasHandleUdpNbtNS(pip, link, &pip->ip_src, &ud->uh_sport,
+                               &alias_address, &alias_port);
 
 /* If UDP checksum is not zero, adjust since source port is */
 /* being aliased and source address is being altered        */
@@ -766,7 +952,7 @@ UdpAliasOut(struct ip *pip)
             sptr = (u_short *) &alias_address;
             accumulate -= *sptr++;
             accumulate -= *sptr;
-            ADJUST_CHECKSUM(accumulate, ud->uh_sum)
+            ADJUST_CHECKSUM(accumulate, ud->uh_sum);
         }
 
 /* Put alias port in UDP header */
@@ -796,7 +982,8 @@ TcpAliasIn(struct ip *pip)
 
     link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
                         tc->th_sport, tc->th_dport,
-                        IPPROTO_TCP);
+                        IPPROTO_TCP,
+                        !(packetAliasMode & PKT_ALIAS_PROXY_ONLY));
     if (link != NULL)
     {
         struct in_addr alias_address;
@@ -807,6 +994,11 @@ TcpAliasIn(struct ip *pip)
         int accumulate;
         u_short *sptr;
 
+/* Special processing for IP encoding protocols */
+        if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
+         || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
+            AliasHandlePptpIn(pip, link);
+
         alias_address = GetAliasAddress(link);
         original_address = GetOriginalAddress(link);
         proxy_address = GetProxyAddress(link);
@@ -825,7 +1017,7 @@ TcpAliasIn(struct ip *pip)
         accumulate -= *sptr++;
         accumulate -= *sptr;
 
-/* If this is a proxy, then modify the tcp source port  and
+/* If this is a proxy, then modify the TCP source port and
    checksum accumulation */
         if (proxy_port != 0)
         {
@@ -841,7 +1033,7 @@ TcpAliasIn(struct ip *pip)
             accumulate -= *sptr;
         }
 
-/* See if ack number needs to be modified */
+/* See if ACK number needs to be modified */
         if (GetAckModified(link) == 1)
         {
             int delta;
@@ -912,7 +1104,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
         return PKT_ALIAS_OK;
 
 /* If this is a transparent proxy, save original destination,
-   then alter the destination and adust checksums */
+   then alter the destination and adjust checksums */
     dest_port = tc->th_dport;
     dest_address = pip->ip_dst;
     if (proxy_type != 0)
@@ -946,7 +1138,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
 
     link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
                          tc->th_sport, tc->th_dport,
-                         IPPROTO_TCP);
+                         IPPROTO_TCP, 1);
     if (link !=NULL)
     {
         u_short alias_port;
@@ -967,16 +1159,24 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
         alias_port = GetAliasPort(link);
         alias_address = GetAliasAddress(link);
 
-/* Monitor tcp connection state */
+/* Monitor TCP connection state */
         TcpMonitorOut(pip, link);
 
 /* Special processing for IP encoding protocols */
         if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
          || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
             AliasHandleFtpOut(pip, link, maxpacketsize);
-        if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
+        else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
          || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
             AliasHandleIrcOut(pip, link, maxpacketsize);
+        else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
+         || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
+         || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
+         || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2) 
+            AliasHandleRtspOut(pip, link, maxpacketsize);
+        else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
+         || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
+            AliasHandlePptpOut(pip, link);
 
 /* Adjust TCP checksum since source port is being aliased */
 /* and source address is being altered                    */
@@ -1009,7 +1209,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
             }
         }
 
-        ADJUST_CHECKSUM(accumulate, tc->th_sum)
+        ADJUST_CHECKSUM(accumulate, tc->th_sum);
 
 /* Change source address */
         sptr = (u_short *) &(pip->ip_src);
@@ -1020,7 +1220,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
         accumulate -= *sptr++;
         accumulate -= *sptr;
 
-        ADJUST_CHECKSUM(accumulate, pip->ip_sum)
+        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
 
         return(PKT_ALIAS_OK);
     }
@@ -1037,7 +1237,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize)
 
 The packet aliasing module has a limited ability for handling IP
 fragments.  If the ICMP, TCP or UDP header is in the first fragment
-received, then the id number of the IP packet is saved, and other
+received, then the ID number of the IP packet is saved, and other
 fragments are identified according to their ID number and IP address
 they were sent from.  Pointers to unresolved fragments can also be
 saved and recalled when a header fragment is seen.
@@ -1098,6 +1298,7 @@ FragmentOut(struct ip *pip)
         PacketAliasFragmentIn()
         PacketAliasIn()
         PacketAliasOut()
+        PacketUnaliasOut()
 
 (prototypes in alias.h)
 */
@@ -1174,8 +1375,12 @@ PacketAliasIn(char *ptr, int maxpacketsize)
     struct ip *pip;
     int iresult;
 
-    if (packetAliasMode & PKT_ALIAS_REVERSE)
-        return PacketAliasOut(ptr, maxpacketsize);
+    if (packetAliasMode & PKT_ALIAS_REVERSE) {
+        packetAliasMode &= ~PKT_ALIAS_REVERSE;
+        iresult = PacketAliasOut(ptr, maxpacketsize);
+        packetAliasMode |= PKT_ALIAS_REVERSE;
+        return iresult;
+    }
 
     HouseKeeping();
     ClearCheckNewLink();
@@ -1202,7 +1407,14 @@ PacketAliasIn(char *ptr, int maxpacketsize)
                 iresult = TcpAliasIn(pip);
                 break;
             case IPPROTO_GRE:
-               iresult = PptpAliasIn(pip);
+               if (packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
+                   AliasHandlePptpGreIn(pip) == 0)
+                   iresult = PKT_ALIAS_OK;
+               else
+                   iresult = ProtoAliasIn(pip);
+               break;
+           default:
+               iresult = ProtoAliasIn(pip);
                 break;
         }
 
@@ -1256,8 +1468,12 @@ PacketAliasOut(char *ptr,           /* valid IP packet */
     struct in_addr addr_save;
     struct ip *pip;
 
-    if (packetAliasMode & PKT_ALIAS_REVERSE)
-        return PacketAliasIn(ptr, maxpacketsize);
+    if (packetAliasMode & PKT_ALIAS_REVERSE) {
+        packetAliasMode &= ~PKT_ALIAS_REVERSE;
+        iresult = PacketAliasIn(ptr, maxpacketsize);
+        packetAliasMode |= PKT_ALIAS_REVERSE;
+        return iresult;
+    }
 
     HouseKeeping();
     ClearCheckNewLink();
@@ -1271,7 +1487,7 @@ PacketAliasOut(char *ptr,           /* valid IP packet */
     addr_save = GetDefaultAliasAddress();
     if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY)
     {
-        unsigned int addr;
+        in_addr_t addr;
         int iclass;
 
         iclass = 0;
@@ -1303,8 +1519,14 @@ PacketAliasOut(char *ptr,           /* valid IP packet */
             case IPPROTO_TCP:
                 iresult = TcpAliasOut(pip, maxpacketsize);
                 break;
-            case IPPROTO_GRE:
-               iresult = PptpAliasOut(pip);
+           case IPPROTO_GRE:
+               if (AliasHandlePptpGreOut(pip) == 0)
+                   iresult = PKT_ALIAS_OK;
+               else
+                   iresult = ProtoAliasOut(pip);
+               break;
+           default:
+               iresult = ProtoAliasOut(pip);
                 break;
         }
     }
@@ -1316,3 +1538,124 @@ PacketAliasOut(char *ptr,           /* valid IP packet */
     SetDefaultAliasAddress(addr_save);
     return(iresult);
 }
+
+int
+PacketUnaliasOut(char *ptr,           /* valid IP packet */
+                 int  maxpacketsize   /* for error checking */
+                )
+{
+    struct ip          *pip;
+    struct icmp        *ic;
+    struct udphdr      *ud;
+    struct tcphdr      *tc;
+    struct alias_link  *link;
+    int                iresult = PKT_ALIAS_IGNORED;
+
+    pip = (struct ip *) ptr;
+
+    /* Defense against mangled packets */
+    if (ntohs(pip->ip_len) > maxpacketsize
+     || (pip->ip_hl<<2) > maxpacketsize)
+        return(iresult);
+
+    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
+    tc = (struct tcphdr *) ud;
+    ic = (struct icmp *) ud;
+
+    /* Find a link */
+    if (pip->ip_p == IPPROTO_UDP)
+        link = FindUdpTcpIn(pip->ip_dst, pip->ip_src,
+                            ud->uh_dport, ud->uh_sport,
+                            IPPROTO_UDP, 0);
+    else if (pip->ip_p == IPPROTO_TCP)
+        link = FindUdpTcpIn(pip->ip_dst, pip->ip_src,
+                            tc->th_dport, tc->th_sport,
+                            IPPROTO_TCP, 0);
+    else if (pip->ip_p == IPPROTO_ICMP) 
+        link = FindIcmpIn(pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
+    else
+        link = NULL;
+
+    /* Change it from an aliased packet to an unaliased packet */
+    if (link != NULL)
+    {
+        if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP)
+        {
+            u_short        *sptr;
+            int           accumulate;
+            struct in_addr original_address;
+            u_short        original_port;
+
+            original_address = GetOriginalAddress(link);
+            original_port = GetOriginalPort(link);
+    
+            /* Adjust TCP/UDP checksum */
+            sptr = (u_short *) &(pip->ip_src);
+            accumulate  = *sptr++;
+            accumulate += *sptr;
+            sptr = (u_short *) &original_address;
+            accumulate -= *sptr++;
+            accumulate -= *sptr;
+
+            if (pip->ip_p == IPPROTO_UDP) {
+                accumulate += ud->uh_sport;
+                accumulate -= original_port;
+                ADJUST_CHECKSUM(accumulate, ud->uh_sum);
+           } else { 
+                accumulate += tc->th_sport;
+                accumulate -= original_port;
+                ADJUST_CHECKSUM(accumulate, tc->th_sum);
+           }
+
+            /* Adjust IP checksum */
+            DifferentialChecksum(&pip->ip_sum,
+                                 (u_short *) &original_address,
+                                 (u_short *) &pip->ip_src,
+                                 2);
+
+            /* Un-alias source address and port number */ 
+            pip->ip_src = original_address;
+            if (pip->ip_p == IPPROTO_UDP) 
+                ud->uh_sport = original_port; 
+           else   
+                tc->th_sport = original_port; 
+            
+           iresult = PKT_ALIAS_OK;
+
+        } else if (pip->ip_p == IPPROTO_ICMP) {
+
+            u_short        *sptr;
+            int            accumulate;
+            struct in_addr original_address;
+            u_short        original_id;
+
+            original_address = GetOriginalAddress(link);
+            original_id = GetOriginalPort(link);
+
+            /* Adjust ICMP checksum */
+            sptr = (u_short *) &(pip->ip_src);
+            accumulate  = *sptr++;
+            accumulate += *sptr;
+            sptr = (u_short *) &original_address;
+            accumulate -= *sptr++;
+            accumulate -= *sptr;
+            accumulate += ic->icmp_id;
+            accumulate -= original_id;
+            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
+
+            /* Adjust IP checksum */
+            DifferentialChecksum(&pip->ip_sum,
+                                 (u_short *) &original_address,
+                                 (u_short *) &pip->ip_src,
+                                 2);
+
+            /* Un-alias source address and port number */
+            pip->ip_src = original_address;
+            ic->icmp_id = original_id;
+
+           iresult = PKT_ALIAS_OK;
+        }
+    }
+    return(iresult);
+
+}