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