alias.c revision 59726
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 does 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    Version 2.3 Dec 1998 (dillon)
77	- Major bounds checking additions, see FreeBSD/CVS
78
79    See HISTORY file for additional revisions.
80
81    $FreeBSD: head/sys/netinet/libalias/alias.c 59726 2000-04-28 13:44:49Z ru $
82*/
83
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#ifndef IPPROTO_GRE
94#define IPPROTO_GRE 47
95#define IPPROTO_ESP 50
96#define IPPROTO_AH  51
97#endif
98
99#include "alias_local.h"
100#include "alias.h"
101
102#define NETBIOS_NS_PORT_NUMBER 137
103#define NETBIOS_DGM_PORT_NUMBER 138
104#define FTP_CONTROL_PORT_NUMBER 21
105#define IRC_CONTROL_PORT_NUMBER_1 6667
106#define IRC_CONTROL_PORT_NUMBER_2 6668
107#define CUSEEME_PORT_NUMBER 7648
108
109
110
111
112/* TCP Handling Routines
113
114    TcpMonitorIn()  -- These routines monitor TCP connections, and
115    TcpMonitorOut()    delete a link when a connection is closed.
116
117These routines look for SYN, FIN and RST flags to determine when TCP
118connections open and close.  When a TCP connection closes, the data
119structure containing packet aliasing information is deleted after
120a timeout period.
121*/
122
123/* Local prototypes */
124static void TcpMonitorIn(struct ip *, struct alias_link *);
125
126static void TcpMonitorOut(struct ip *, struct alias_link *);
127
128
129static void
130TcpMonitorIn(struct ip *pip, struct alias_link *link)
131{
132    struct tcphdr *tc;
133
134    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
135
136    switch (GetStateIn(link))
137    {
138        case ALIAS_TCP_STATE_NOT_CONNECTED:
139            if (tc->th_flags & TH_RST)
140                SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
141            else if (tc->th_flags & TH_SYN)
142                SetStateIn(link, ALIAS_TCP_STATE_CONNECTED);
143            break;
144        case ALIAS_TCP_STATE_CONNECTED:
145            if (tc->th_flags & (TH_FIN | TH_RST))
146                SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
147            break;
148    }
149}
150
151static void
152TcpMonitorOut(struct ip *pip, struct alias_link *link)
153{
154    struct tcphdr *tc;
155
156    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
157
158    switch (GetStateOut(link))
159    {
160        case ALIAS_TCP_STATE_NOT_CONNECTED:
161            if (tc->th_flags & TH_RST)
162                SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
163            else if (tc->th_flags & TH_SYN)
164                SetStateOut(link, ALIAS_TCP_STATE_CONNECTED);
165            break;
166        case ALIAS_TCP_STATE_CONNECTED:
167            if (tc->th_flags & (TH_FIN | TH_RST))
168                SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
169            break;
170    }
171}
172
173
174
175
176
177/* Protocol Specific Packet Aliasing Routines
178
179    IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3()
180    IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3()
181    ProtoAliasIn(), ProtoAliasOut()
182    UdpAliasIn(), UdpAliasOut()
183    TcpAliasIn(), TcpAliasOut()
184
185These routines handle protocol specific details of packet aliasing.
186One may observe a certain amount of repetitive arithmetic in these
187functions, the purpose of which is to compute a revised checksum
188without actually summing over the entire data packet, which could be
189unnecessarily time consuming.
190
191The purpose of the packet aliasing routines is to replace the source
192address of the outgoing packet and then correctly put it back for
193any incoming packets.  For TCP and UDP, ports are also re-mapped.
194
195For ICMP echo/timestamp requests and replies, the following scheme
196is used: the ID number is replaced by an alias for the outgoing
197packet.
198
199ICMP error messages are handled by looking at the IP fragment
200in the data section of the message.
201
202For TCP and UDP protocols, a port number is chosen for an outgoing
203packet, and then incoming packets are identified by IP address and
204port numbers.  For TCP packets, there is additional logic in the event
205that sequence and ACK numbers have been altered (as in the case for
206FTP data port commands).
207
208The port numbers used by the packet aliasing module are not true
209ports in the Unix sense.  No sockets are actually bound to ports.
210They are more correctly thought of as placeholders.
211
212All packets go through the aliasing mechanism, whether they come from
213the gateway machine or other machines on a local area network.
214*/
215
216
217/* Local prototypes */
218static int IcmpAliasIn1(struct ip *);
219static int IcmpAliasIn2(struct ip *);
220static int IcmpAliasIn3(struct ip *);
221static int IcmpAliasIn (struct ip *);
222
223static int IcmpAliasOut1(struct ip *);
224static int IcmpAliasOut2(struct ip *);
225static int IcmpAliasOut3(struct ip *);
226static int IcmpAliasOut (struct ip *);
227
228static int ProtoAliasIn(struct ip *);
229static int ProtoAliasOut(struct ip *);
230
231static int UdpAliasOut(struct ip *);
232static int UdpAliasIn (struct ip *);
233
234static int TcpAliasOut(struct ip *, int);
235static int TcpAliasIn (struct ip *);
236
237
238static int
239IcmpAliasIn1(struct ip *pip)
240{
241/*
242    De-alias incoming echo and timestamp replies
243*/
244    struct alias_link *link;
245    struct icmp *ic;
246
247    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
248
249/* Get source address from ICMP data field and restore original data */
250    link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id);
251    if (link != NULL)
252    {
253        u_short original_id;
254        int accumulate;
255
256        original_id = GetOriginalPort(link);
257
258/* Adjust ICMP checksum */
259        accumulate  = ic->icmp_id;
260        accumulate -= original_id;
261        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
262
263/* Put original sequence number back in */
264        ic->icmp_id = original_id;
265
266/* Put original address back into IP header */
267        {
268            struct in_addr original_address;
269
270            original_address = GetOriginalAddress(link);
271            DifferentialChecksum(&pip->ip_sum,
272                                 (u_short *) &original_address,
273                                 (u_short *) &pip->ip_dst,
274                                 2);
275            pip->ip_dst = original_address;
276        }
277
278        return(PKT_ALIAS_OK);
279    }
280    return(PKT_ALIAS_IGNORED);
281}
282
283static int
284IcmpAliasIn2(struct ip *pip)
285{
286/*
287    Alias incoming ICMP error messages containing
288    IP header and first 64 bits of datagram.
289*/
290    struct ip *ip;
291    struct icmp *ic, *ic2;
292    struct udphdr *ud;
293    struct tcphdr *tc;
294    struct alias_link *link;
295
296    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
297    ip = (struct ip *) ic->icmp_data;
298
299    ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
300    tc = (struct tcphdr *) ud;
301    ic2 = (struct icmp *) ud;
302
303    if (ip->ip_p == IPPROTO_UDP)
304        link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
305                            ud->uh_dport, ud->uh_sport,
306                            IPPROTO_UDP);
307    else if (ip->ip_p == IPPROTO_TCP)
308        link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
309                            tc->th_dport, tc->th_sport,
310                            IPPROTO_TCP);
311    else if (ip->ip_p == IPPROTO_ICMP) {
312        if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
313            link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id);
314        else
315            link = NULL;
316    } else
317        link = NULL;
318
319    if (link != NULL)
320    {
321        if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
322        {
323            u_short *sptr;
324            int accumulate;
325            struct in_addr original_address;
326            u_short original_port;
327
328            original_address = GetOriginalAddress(link);
329            original_port = GetOriginalPort(link);
330
331/* Adjust ICMP checksum */
332            sptr = (u_short *) &(ip->ip_src);
333            accumulate  = *sptr++;
334            accumulate += *sptr;
335            sptr = (u_short *) &original_address;
336            accumulate -= *sptr++;
337            accumulate -= *sptr;
338            accumulate += ud->uh_sport;
339            accumulate -= original_port;
340            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
341
342/* Un-alias address in IP header */
343            DifferentialChecksum(&pip->ip_sum,
344                                 (u_short *) &original_address,
345                                 (u_short *) &pip->ip_dst,
346                                 2);
347            pip->ip_dst = original_address;
348
349/* Un-alias address and port number of original IP packet
350fragment contained in ICMP data section */
351            ip->ip_src = original_address;
352            ud->uh_sport = original_port;
353        }
354        else if (pip->ip_p == IPPROTO_ICMP)
355        {
356            u_short *sptr;
357            int accumulate;
358            struct in_addr original_address;
359            u_short original_id;
360
361            original_address = GetOriginalAddress(link);
362            original_id = GetOriginalPort(link);
363
364/* Adjust ICMP checksum */
365            sptr = (u_short *) &(ip->ip_src);
366            accumulate  = *sptr++;
367            accumulate += *sptr;
368            sptr = (u_short *) &original_address;
369            accumulate -= *sptr++;
370            accumulate -= *sptr;
371            accumulate += ic2->icmp_id;
372            accumulate -= original_id;
373            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
374
375/* Un-alias address in IP header */
376            DifferentialChecksum(&pip->ip_sum,
377                                 (u_short *) &original_address,
378                                 (u_short *) &pip->ip_dst,
379                                 2);
380            pip->ip_dst = original_address;
381
382/* Un-alias address of original IP packet and sequence number of
383   embedded ICMP datagram */
384            ip->ip_src = original_address;
385            ic2->icmp_id = original_id;
386        }
387        return(PKT_ALIAS_OK);
388    }
389    return(PKT_ALIAS_IGNORED);
390}
391
392static int
393IcmpAliasIn3(struct ip *pip)
394{
395    struct in_addr original_address;
396
397    original_address = FindOriginalAddress(pip->ip_dst);
398    DifferentialChecksum(&pip->ip_sum,
399                         (u_short *) &original_address,
400                         (u_short *) &pip->ip_dst,
401                         2);
402    pip->ip_dst = original_address;
403
404    return PKT_ALIAS_OK;
405}
406
407
408static int
409IcmpAliasIn(struct ip *pip)
410{
411    int iresult;
412    struct icmp *ic;
413
414/* Return if proxy-only mode is enabled */
415    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
416        return PKT_ALIAS_OK;
417
418    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
419
420    iresult = PKT_ALIAS_IGNORED;
421    switch (ic->icmp_type)
422    {
423        case ICMP_ECHOREPLY:
424        case ICMP_TSTAMPREPLY:
425            if (ic->icmp_code == 0)
426            {
427                iresult = IcmpAliasIn1(pip);
428            }
429            break;
430        case ICMP_UNREACH:
431        case ICMP_SOURCEQUENCH:
432        case ICMP_TIMXCEED:
433        case ICMP_PARAMPROB:
434            iresult = IcmpAliasIn2(pip);
435            break;
436        case ICMP_ECHO:
437        case ICMP_TSTAMP:
438            iresult = IcmpAliasIn3(pip);
439            break;
440    }
441    return(iresult);
442}
443
444
445static int
446IcmpAliasOut1(struct ip *pip)
447{
448/*
449    Alias ICMP echo and timestamp packets
450*/
451    struct alias_link *link;
452    struct icmp *ic;
453
454    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
455
456/* Save overwritten data for when echo packet returns */
457    link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id);
458    if (link != NULL)
459    {
460        u_short alias_id;
461        int accumulate;
462
463        alias_id = GetAliasPort(link);
464
465/* Since data field is being modified, adjust ICMP checksum */
466        accumulate  = ic->icmp_id;
467        accumulate -= alias_id;
468        ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
469
470/* Alias sequence number */
471        ic->icmp_id = alias_id;
472
473/* Change source address */
474        {
475            struct in_addr alias_address;
476
477            alias_address = GetAliasAddress(link);
478            DifferentialChecksum(&pip->ip_sum,
479                                 (u_short *) &alias_address,
480                                 (u_short *) &pip->ip_src,
481                                 2);
482            pip->ip_src = alias_address;
483        }
484
485        return(PKT_ALIAS_OK);
486    }
487    return(PKT_ALIAS_IGNORED);
488}
489
490
491static int
492IcmpAliasOut2(struct ip *pip)
493{
494/*
495    Alias outgoing ICMP error messages containing
496    IP header and first 64 bits of datagram.
497*/
498    struct ip *ip;
499    struct icmp *ic, *ic2;
500    struct udphdr *ud;
501    struct tcphdr *tc;
502    struct alias_link *link;
503
504    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
505    ip = (struct ip *) ic->icmp_data;
506
507    ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
508    tc = (struct tcphdr *) ud;
509    ic2 = (struct icmp *) ud;
510
511    if (ip->ip_p == IPPROTO_UDP)
512        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
513                            ud->uh_dport, ud->uh_sport,
514                            IPPROTO_UDP);
515    else if (ip->ip_p == IPPROTO_TCP)
516        link = FindUdpTcpOut(ip->ip_dst, ip->ip_src,
517                            tc->th_dport, tc->th_sport,
518                            IPPROTO_TCP);
519    else if (ip->ip_p == IPPROTO_ICMP) {
520        if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
521            link = FindIcmpOut(ip->ip_dst, ip->ip_src, ic2->icmp_id);
522        else
523            link = NULL;
524    } else
525        link = NULL;
526
527    if (link != NULL)
528    {
529        if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
530        {
531            u_short *sptr;
532            int accumulate;
533            struct in_addr alias_address;
534            u_short alias_port;
535
536            alias_address = GetAliasAddress(link);
537            alias_port = GetAliasPort(link);
538
539/* Adjust ICMP checksum */
540            sptr = (u_short *) &(ip->ip_dst);
541            accumulate  = *sptr++;
542            accumulate += *sptr;
543            sptr = (u_short *) &alias_address;
544            accumulate -= *sptr++;
545            accumulate -= *sptr;
546            accumulate += ud->uh_dport;
547            accumulate -= alias_port;
548            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
549
550/* Alias address in IP header */
551            DifferentialChecksum(&pip->ip_sum,
552                                 (u_short *) &alias_address,
553                                 (u_short *) &pip->ip_src,
554                                 2);
555            pip->ip_src = alias_address;
556
557/* Alias address and port number of original IP packet
558fragment contained in ICMP data section */
559            ip->ip_dst = alias_address;
560            ud->uh_dport = alias_port;
561        }
562        else if (pip->ip_p == IPPROTO_ICMP)
563        {
564            u_short *sptr;
565            int accumulate;
566            struct in_addr alias_address;
567            u_short alias_id;
568
569            alias_address = GetAliasAddress(link);
570            alias_id = GetAliasPort(link);
571
572/* Adjust ICMP checksum */
573            sptr = (u_short *) &(ip->ip_dst);
574            accumulate  = *sptr++;
575            accumulate += *sptr;
576            sptr = (u_short *) &alias_address;
577            accumulate -= *sptr++;
578            accumulate -= *sptr;
579            accumulate += ic2->icmp_id;
580            accumulate -= alias_id;
581            ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
582
583/* Alias address in IP header */
584            DifferentialChecksum(&pip->ip_sum,
585                                 (u_short *) &alias_address,
586                                 (u_short *) &pip->ip_src,
587                                 2);
588            pip->ip_src = alias_address;
589
590/* Alias address of original IP packet and sequence number of
591   embedded ICMP datagram */
592            ip->ip_dst = alias_address;
593            ic2->icmp_id = alias_id;
594        }
595        return(PKT_ALIAS_OK);
596    }
597    return(PKT_ALIAS_IGNORED);
598}
599
600
601static int
602IcmpAliasOut3(struct ip *pip)
603{
604/*
605  Handle outgoing echo and timestamp replies.  The
606  only thing which is done in this case is to alias
607  the source IP address of the packet.
608*/
609    struct in_addr alias_addr;
610
611    alias_addr = FindAliasAddress(pip->ip_src);
612    DifferentialChecksum(&pip->ip_sum,
613                         (u_short *) &alias_addr,
614                         (u_short *) &pip->ip_src,
615                         2);
616    pip->ip_src = alias_addr;
617
618    return PKT_ALIAS_OK;
619}
620
621
622static int
623IcmpAliasOut(struct ip *pip)
624{
625    int iresult;
626    struct icmp *ic;
627
628/* Return if proxy-only mode is enabled */
629    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
630        return PKT_ALIAS_OK;
631
632    ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
633
634    iresult = PKT_ALIAS_IGNORED;
635    switch (ic->icmp_type)
636    {
637        case ICMP_ECHO:
638        case ICMP_TSTAMP:
639            if (ic->icmp_code == 0)
640            {
641                iresult = IcmpAliasOut1(pip);
642            }
643            break;
644        case ICMP_UNREACH:
645        case ICMP_SOURCEQUENCH:
646        case ICMP_TIMXCEED:
647        case ICMP_PARAMPROB:
648            iresult = IcmpAliasOut2(pip);
649            break;
650        case ICMP_ECHOREPLY:
651        case ICMP_TSTAMPREPLY:
652            iresult = IcmpAliasOut3(pip);
653    }
654    return(iresult);
655}
656
657
658
659static int
660ProtoAliasIn(struct ip *pip)
661{
662/*
663  Handle incoming IP packets. The
664  only thing which is done in this case is to alias
665  the dest IP address of the packet to our inside
666  machine.
667*/
668    struct alias_link *link;
669
670/* Return if proxy-only mode is enabled */
671    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
672        return PKT_ALIAS_OK;
673
674    link = FindProtoIn(pip->ip_src, pip->ip_dst, pip->ip_p);
675    if (link != NULL)
676    {
677        struct in_addr original_address;
678
679        original_address = GetOriginalAddress(link);
680
681/* Restore original IP address */
682        DifferentialChecksum(&pip->ip_sum,
683                             (u_short *) &original_address,
684                             (u_short *) &pip->ip_dst,
685                             2);
686        pip->ip_dst = original_address;
687
688	return(PKT_ALIAS_OK);
689    }
690    return(PKT_ALIAS_IGNORED);
691}
692
693
694static int
695ProtoAliasOut(struct ip *pip)
696{
697/*
698  Handle outgoing IP packets. The
699  only thing which is done in this case is to alias
700  the source IP address of the packet.
701*/
702    struct alias_link *link;
703
704/* Return if proxy-only mode is enabled */
705    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
706        return PKT_ALIAS_OK;
707
708    link = FindProtoOut(pip->ip_src, pip->ip_dst, pip->ip_p);
709    if (link != NULL)
710    {
711        struct in_addr alias_address;
712
713        alias_address = GetAliasAddress(link);
714
715/* Change source address */
716        DifferentialChecksum(&pip->ip_sum,
717                             (u_short *) &alias_address,
718                             (u_short *) &pip->ip_src,
719                             2);
720        pip->ip_src = alias_address;
721
722        return(PKT_ALIAS_OK);
723    }
724    return(PKT_ALIAS_IGNORED);
725}
726
727
728
729static int
730UdpAliasIn(struct ip *pip)
731{
732    struct udphdr *ud;
733    struct alias_link *link;
734
735/* Return if proxy-only mode is enabled */
736    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
737        return PKT_ALIAS_OK;
738
739    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
740
741    link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
742                        ud->uh_sport, ud->uh_dport,
743                        IPPROTO_UDP);
744    if (link != NULL)
745    {
746        struct in_addr alias_address;
747        struct in_addr original_address;
748        u_short alias_port;
749        int accumulate;
750        u_short *sptr;
751	int r = 0;
752
753        alias_address = GetAliasAddress(link);
754        original_address = GetOriginalAddress(link);
755        alias_port = ud->uh_dport;
756        ud->uh_dport = GetOriginalPort(link);
757
758/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
759		if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
760         || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
761		{
762            r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
763		} else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
764         || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
765		{
766            r = AliasHandleUdpNbtNS(pip, link,
767								&alias_address,
768								&alias_port,
769								&original_address,
770								&ud->uh_dport );
771		}
772
773        if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
774            AliasHandleCUSeeMeIn(pip, original_address);
775
776/* If UDP checksum is not zero, then adjust since destination port */
777/* is being unaliased and destination port is being altered.       */
778        if (ud->uh_sum != 0)
779        {
780            accumulate  = alias_port;
781            accumulate -= ud->uh_dport;
782            sptr = (u_short *) &alias_address;
783            accumulate += *sptr++;
784            accumulate += *sptr;
785            sptr = (u_short *) &original_address;
786            accumulate -= *sptr++;
787            accumulate -= *sptr;
788            ADJUST_CHECKSUM(accumulate, ud->uh_sum)
789        }
790
791/* Restore original IP address */
792        DifferentialChecksum(&pip->ip_sum,
793                             (u_short *) &original_address,
794                             (u_short *) &pip->ip_dst,
795                             2);
796        pip->ip_dst = original_address;
797
798	/*
799	 * If we cannot figure out the packet, ignore it.
800	 */
801	if (r < 0)
802	    return(PKT_ALIAS_IGNORED);
803	else
804	    return(PKT_ALIAS_OK);
805    }
806    return(PKT_ALIAS_IGNORED);
807}
808
809static int
810UdpAliasOut(struct ip *pip)
811{
812    struct udphdr *ud;
813    struct alias_link *link;
814
815/* Return if proxy-only mode is enabled */
816    if (packetAliasMode & PKT_ALIAS_PROXY_ONLY)
817        return PKT_ALIAS_OK;
818
819    ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
820
821    link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
822                         ud->uh_sport, ud->uh_dport,
823                         IPPROTO_UDP);
824    if (link != NULL)
825    {
826        u_short alias_port;
827        struct in_addr alias_address;
828
829        alias_address = GetAliasAddress(link);
830        alias_port = GetAliasPort(link);
831
832        if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
833            AliasHandleCUSeeMeOut(pip, link);
834
835/* If NETBIOS Datagram, It should be alias address in UDP Data, too */
836		if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
837         || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
838		{
839            AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
840		} else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
841         || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
842		{
843            AliasHandleUdpNbtNS(pip, link,
844								&pip->ip_src,
845								&ud->uh_sport,
846							    &alias_address,
847							 	&alias_port);
848		}
849
850/* If UDP checksum is not zero, adjust since source port is */
851/* being aliased and source address is being altered        */
852        if (ud->uh_sum != 0)
853        {
854            int accumulate;
855            u_short *sptr;
856
857            accumulate  = ud->uh_sport;
858            accumulate -= alias_port;
859            sptr = (u_short *) &(pip->ip_src);
860            accumulate += *sptr++;
861            accumulate += *sptr;
862            sptr = (u_short *) &alias_address;
863            accumulate -= *sptr++;
864            accumulate -= *sptr;
865            ADJUST_CHECKSUM(accumulate, ud->uh_sum)
866        }
867
868/* Put alias port in UDP header */
869        ud->uh_sport = alias_port;
870
871/* Change source address */
872        DifferentialChecksum(&pip->ip_sum,
873                             (u_short *) &alias_address,
874                             (u_short *) &pip->ip_src,
875                             2);
876        pip->ip_src = alias_address;
877
878        return(PKT_ALIAS_OK);
879    }
880    return(PKT_ALIAS_IGNORED);
881}
882
883
884
885static int
886TcpAliasIn(struct ip *pip)
887{
888    struct tcphdr *tc;
889    struct alias_link *link;
890
891    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
892
893    link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
894                        tc->th_sport, tc->th_dport,
895                        IPPROTO_TCP);
896    if (link != NULL)
897    {
898        struct in_addr alias_address;
899        struct in_addr original_address;
900        struct in_addr proxy_address;
901        u_short alias_port;
902        u_short proxy_port;
903        int accumulate;
904        u_short *sptr;
905
906        alias_address = GetAliasAddress(link);
907        original_address = GetOriginalAddress(link);
908        proxy_address = GetProxyAddress(link);
909        alias_port = tc->th_dport;
910        tc->th_dport = GetOriginalPort(link);
911        proxy_port = GetProxyPort(link);
912
913/* Adjust TCP checksum since destination port is being unaliased */
914/* and destination port is being altered.                        */
915        accumulate  = alias_port;
916        accumulate -= tc->th_dport;
917        sptr = (u_short *) &alias_address;
918        accumulate += *sptr++;
919        accumulate += *sptr;
920        sptr = (u_short *) &original_address;
921        accumulate -= *sptr++;
922        accumulate -= *sptr;
923
924/* If this is a proxy, then modify the TCP source port and
925   checksum accumulation */
926        if (proxy_port != 0)
927        {
928            accumulate += tc->th_sport;
929            tc->th_sport = proxy_port;
930            accumulate -= tc->th_sport;
931
932            sptr = (u_short *) &pip->ip_src;
933            accumulate += *sptr++;
934            accumulate += *sptr;
935            sptr = (u_short *) &proxy_address;
936            accumulate -= *sptr++;
937            accumulate -= *sptr;
938        }
939
940/* See if ACK number needs to be modified */
941        if (GetAckModified(link) == 1)
942        {
943            int delta;
944
945            delta = GetDeltaAckIn(pip, link);
946            if (delta != 0)
947            {
948                sptr = (u_short *) &tc->th_ack;
949                accumulate += *sptr++;
950                accumulate += *sptr;
951                tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
952                sptr = (u_short *) &tc->th_ack;
953                accumulate -= *sptr++;
954                accumulate -= *sptr;
955            }
956        }
957
958        ADJUST_CHECKSUM(accumulate, tc->th_sum);
959
960/* Restore original IP address */
961        sptr = (u_short *) &pip->ip_dst;
962        accumulate  = *sptr++;
963        accumulate += *sptr;
964        pip->ip_dst = original_address;
965        sptr = (u_short *) &pip->ip_dst;
966        accumulate -= *sptr++;
967        accumulate -= *sptr;
968
969/* If this is a transparent proxy packet, then modify the source
970   address */
971        if (proxy_address.s_addr != 0)
972        {
973            sptr = (u_short *) &pip->ip_src;
974            accumulate += *sptr++;
975            accumulate += *sptr;
976            pip->ip_src = proxy_address;
977            sptr = (u_short *) &pip->ip_src;
978            accumulate -= *sptr++;
979            accumulate -= *sptr;
980        }
981
982        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
983
984/* Monitor TCP connection state */
985        TcpMonitorIn(pip, link);
986
987        return(PKT_ALIAS_OK);
988    }
989    return(PKT_ALIAS_IGNORED);
990}
991
992static int
993TcpAliasOut(struct ip *pip, int maxpacketsize)
994{
995    int proxy_type;
996    u_short dest_port;
997    u_short proxy_server_port;
998    struct in_addr dest_address;
999    struct in_addr proxy_server_address;
1000    struct tcphdr *tc;
1001    struct alias_link *link;
1002
1003    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1004
1005    proxy_type = ProxyCheck(pip, &proxy_server_address, &proxy_server_port);
1006
1007    if (proxy_type == 0 && (packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1008        return PKT_ALIAS_OK;
1009
1010/* If this is a transparent proxy, save original destination,
1011   then alter the destination and adjust checksums */
1012    dest_port = tc->th_dport;
1013    dest_address = pip->ip_dst;
1014    if (proxy_type != 0)
1015    {
1016        int accumulate;
1017        u_short *sptr;
1018
1019        accumulate = tc->th_dport;
1020        tc->th_dport = proxy_server_port;
1021        accumulate -= tc->th_dport;
1022
1023        sptr = (u_short *) &(pip->ip_dst);
1024        accumulate += *sptr++;
1025        accumulate += *sptr;
1026        sptr = (u_short *) &proxy_server_address;
1027        accumulate -= *sptr++;
1028        accumulate -= *sptr;
1029
1030        ADJUST_CHECKSUM(accumulate, tc->th_sum);
1031
1032        sptr = (u_short *) &(pip->ip_dst);
1033        accumulate  = *sptr++;
1034        accumulate += *sptr;
1035        pip->ip_dst = proxy_server_address;
1036        sptr = (u_short *) &(pip->ip_dst);
1037        accumulate -= *sptr++;
1038        accumulate -= *sptr;
1039
1040        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1041    }
1042
1043    link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
1044                         tc->th_sport, tc->th_dport,
1045                         IPPROTO_TCP);
1046    if (link !=NULL)
1047    {
1048        u_short alias_port;
1049        struct in_addr alias_address;
1050        int accumulate;
1051        u_short *sptr;
1052
1053/* Save original destination address, if this is a proxy packet.
1054   Also modify packet to include destination encoding. */
1055        if (proxy_type != 0)
1056        {
1057            SetProxyPort(link, dest_port);
1058            SetProxyAddress(link, dest_address);
1059            ProxyModify(link, pip, maxpacketsize, proxy_type);
1060        }
1061
1062/* Get alias address and port */
1063        alias_port = GetAliasPort(link);
1064        alias_address = GetAliasAddress(link);
1065
1066/* Monitor TCP connection state */
1067        TcpMonitorOut(pip, link);
1068
1069/* Special processing for IP encoding protocols */
1070        if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
1071         || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
1072            AliasHandleFtpOut(pip, link, maxpacketsize);
1073        if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
1074         || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
1075            AliasHandleIrcOut(pip, link, maxpacketsize);
1076
1077/* Adjust TCP checksum since source port is being aliased */
1078/* and source address is being altered                    */
1079        accumulate  = tc->th_sport;
1080        tc->th_sport = alias_port;
1081        accumulate -= tc->th_sport;
1082
1083        sptr = (u_short *) &(pip->ip_src);
1084        accumulate += *sptr++;
1085        accumulate += *sptr;
1086        sptr = (u_short *) &alias_address;
1087        accumulate -= *sptr++;
1088        accumulate -= *sptr;
1089
1090/* Modify sequence number if necessary */
1091        if (GetAckModified(link) == 1)
1092        {
1093            int delta;
1094
1095            delta = GetDeltaSeqOut(pip, link);
1096            if (delta != 0)
1097            {
1098                sptr = (u_short *) &tc->th_seq;
1099                accumulate += *sptr++;
1100                accumulate += *sptr;
1101                tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1102                sptr = (u_short *) &tc->th_seq;
1103                accumulate -= *sptr++;
1104                accumulate -= *sptr;
1105            }
1106        }
1107
1108        ADJUST_CHECKSUM(accumulate, tc->th_sum)
1109
1110/* Change source address */
1111        sptr = (u_short *) &(pip->ip_src);
1112        accumulate  = *sptr++;
1113        accumulate += *sptr;
1114        pip->ip_src = alias_address;
1115        sptr = (u_short *) &(pip->ip_src);
1116        accumulate -= *sptr++;
1117        accumulate -= *sptr;
1118
1119        ADJUST_CHECKSUM(accumulate, pip->ip_sum)
1120
1121        return(PKT_ALIAS_OK);
1122    }
1123    return(PKT_ALIAS_IGNORED);
1124}
1125
1126
1127
1128
1129/* Fragment Handling
1130
1131    FragmentIn()
1132    FragmentOut()
1133
1134The packet aliasing module has a limited ability for handling IP
1135fragments.  If the ICMP, TCP or UDP header is in the first fragment
1136received, then the ID number of the IP packet is saved, and other
1137fragments are identified according to their ID number and IP address
1138they were sent from.  Pointers to unresolved fragments can also be
1139saved and recalled when a header fragment is seen.
1140*/
1141
1142/* Local prototypes */
1143static int FragmentIn(struct ip *);
1144static int FragmentOut(struct ip *);
1145
1146
1147static int
1148FragmentIn(struct ip *pip)
1149{
1150    struct alias_link *link;
1151
1152    link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id);
1153    if (link != NULL)
1154    {
1155        struct in_addr original_address;
1156
1157        GetFragmentAddr(link, &original_address);
1158        DifferentialChecksum(&pip->ip_sum,
1159                             (u_short *) &original_address,
1160                             (u_short *) &pip->ip_dst,
1161                             2);
1162        pip->ip_dst = original_address;
1163
1164        return(PKT_ALIAS_OK);
1165    }
1166    return(PKT_ALIAS_UNRESOLVED_FRAGMENT);
1167}
1168
1169
1170static int
1171FragmentOut(struct ip *pip)
1172{
1173    struct in_addr alias_address;
1174
1175    alias_address = FindAliasAddress(pip->ip_src);
1176    DifferentialChecksum(&pip->ip_sum,
1177                         (u_short *) &alias_address,
1178                         (u_short *) &pip->ip_src,
1179                          2);
1180    pip->ip_src = alias_address;
1181
1182    return(PKT_ALIAS_OK);
1183}
1184
1185
1186
1187
1188
1189
1190/* Outside World Access
1191
1192        PacketAliasSaveFragment()
1193        PacketAliasGetFragment()
1194        PacketAliasFragmentIn()
1195        PacketAliasIn()
1196        PacketAliasOut()
1197
1198(prototypes in alias.h)
1199*/
1200
1201
1202int
1203PacketAliasSaveFragment(char *ptr)
1204{
1205    int iresult;
1206    struct alias_link *link;
1207    struct ip *pip;
1208
1209    pip = (struct ip *) ptr;
1210    link = AddFragmentPtrLink(pip->ip_src, pip->ip_id);
1211    iresult = PKT_ALIAS_ERROR;
1212    if (link != NULL)
1213    {
1214        SetFragmentPtr(link, ptr);
1215        iresult = PKT_ALIAS_OK;
1216    }
1217    return(iresult);
1218}
1219
1220
1221char *
1222PacketAliasGetFragment(char *ptr)
1223{
1224    struct alias_link *link;
1225    char *fptr;
1226    struct ip *pip;
1227
1228    pip = (struct ip *) ptr;
1229    link = FindFragmentPtr(pip->ip_src, pip->ip_id);
1230    if (link != NULL)
1231    {
1232        GetFragmentPtr(link, &fptr);
1233        SetFragmentPtr(link, NULL);
1234        SetExpire(link, 0); /* Deletes link */
1235
1236        return(fptr);
1237    }
1238    else
1239    {
1240        return(NULL);
1241    }
1242}
1243
1244
1245void
1246PacketAliasFragmentIn(char *ptr,          /* Points to correctly de-aliased
1247                                             header fragment */
1248                      char *ptr_fragment  /* Points to fragment which must
1249                                             be de-aliased   */
1250                     )
1251{
1252    struct ip *pip;
1253    struct ip *fpip;
1254
1255    pip = (struct ip *) ptr;
1256    fpip = (struct ip *) ptr_fragment;
1257
1258    DifferentialChecksum(&fpip->ip_sum,
1259                         (u_short *) &pip->ip_dst,
1260                         (u_short *) &fpip->ip_dst,
1261                         2);
1262    fpip->ip_dst = pip->ip_dst;
1263}
1264
1265
1266int
1267PacketAliasIn(char *ptr, int maxpacketsize)
1268{
1269    struct in_addr alias_addr;
1270    struct ip *pip;
1271    int iresult;
1272
1273    if (packetAliasMode & PKT_ALIAS_REVERSE) {
1274        packetAliasMode &= ~PKT_ALIAS_REVERSE;
1275        iresult = PacketAliasOut(ptr, maxpacketsize);
1276        packetAliasMode |= PKT_ALIAS_REVERSE;
1277        return iresult;
1278    }
1279
1280    HouseKeeping();
1281    ClearCheckNewLink();
1282    pip = (struct ip *) ptr;
1283    alias_addr = pip->ip_dst;
1284
1285    /* Defense against mangled packets */
1286    if (ntohs(pip->ip_len) > maxpacketsize
1287     || (pip->ip_hl<<2) > maxpacketsize)
1288        return PKT_ALIAS_IGNORED;
1289
1290    iresult = PKT_ALIAS_IGNORED;
1291    if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 )
1292    {
1293        switch (pip->ip_p)
1294        {
1295            case IPPROTO_ICMP:
1296                iresult = IcmpAliasIn(pip);
1297                break;
1298            case IPPROTO_UDP:
1299                iresult = UdpAliasIn(pip);
1300                break;
1301            case IPPROTO_TCP:
1302                iresult = TcpAliasIn(pip);
1303                break;
1304	    default:
1305		iresult = ProtoAliasIn(pip);
1306                break;
1307        }
1308
1309        if (ntohs(pip->ip_off) & IP_MF)
1310        {
1311            struct alias_link *link;
1312
1313            link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id);
1314            if (link != NULL)
1315            {
1316                iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1317                SetFragmentAddr(link, pip->ip_dst);
1318            }
1319            else
1320            {
1321                iresult = PKT_ALIAS_ERROR;
1322            }
1323        }
1324    }
1325    else
1326    {
1327        iresult = FragmentIn(pip);
1328    }
1329
1330    return(iresult);
1331}
1332
1333
1334
1335/* Unregistered address ranges */
1336
1337/* 10.0.0.0   ->   10.255.255.255 */
1338#define UNREG_ADDR_A_LOWER 0x0a000000
1339#define UNREG_ADDR_A_UPPER 0x0affffff
1340
1341/* 172.16.0.0  ->  172.31.255.255 */
1342#define UNREG_ADDR_B_LOWER 0xac100000
1343#define UNREG_ADDR_B_UPPER 0xac1fffff
1344
1345/* 192.168.0.0 -> 192.168.255.255 */
1346#define UNREG_ADDR_C_LOWER 0xc0a80000
1347#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1348
1349int
1350PacketAliasOut(char *ptr,           /* valid IP packet */
1351               int  maxpacketsize   /* How much the packet data may grow
1352                                       (FTP and IRC inline changes) */
1353              )
1354{
1355    int iresult;
1356    struct in_addr addr_save;
1357    struct ip *pip;
1358
1359    if (packetAliasMode & PKT_ALIAS_REVERSE) {
1360        packetAliasMode &= ~PKT_ALIAS_REVERSE;
1361        iresult = PacketAliasIn(ptr, maxpacketsize);
1362        packetAliasMode |= PKT_ALIAS_REVERSE;
1363        return iresult;
1364    }
1365
1366    HouseKeeping();
1367    ClearCheckNewLink();
1368    pip = (struct ip *) ptr;
1369
1370    /* Defense against mangled packets */
1371    if (ntohs(pip->ip_len) > maxpacketsize
1372     || (pip->ip_hl<<2) > maxpacketsize)
1373        return PKT_ALIAS_IGNORED;
1374
1375    addr_save = GetDefaultAliasAddress();
1376    if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY)
1377    {
1378        u_long addr;
1379        int iclass;
1380
1381        iclass = 0;
1382        addr = ntohl(pip->ip_src.s_addr);
1383        if      (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1384            iclass = 3;
1385        else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1386            iclass = 2;
1387        else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1388            iclass = 1;
1389
1390        if (iclass == 0)
1391        {
1392            SetDefaultAliasAddress(pip->ip_src);
1393        }
1394    }
1395
1396    iresult = PKT_ALIAS_IGNORED;
1397    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0)
1398    {
1399        switch (pip->ip_p)
1400        {
1401            case IPPROTO_ICMP:
1402                iresult = IcmpAliasOut(pip);
1403                break;
1404            case IPPROTO_UDP:
1405                iresult = UdpAliasOut(pip);
1406                break;
1407            case IPPROTO_TCP:
1408                iresult = TcpAliasOut(pip, maxpacketsize);
1409                break;
1410	    default:
1411		iresult = ProtoAliasOut(pip);
1412                break;
1413        }
1414    }
1415    else
1416    {
1417        iresult = FragmentOut(pip);
1418    }
1419
1420    SetDefaultAliasAddress(addr_save);
1421    return(iresult);
1422}
1423