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