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