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