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