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