xref: /freebsd/sys/netinet/libalias/alias.c (revision 59519ca74f1abcdd8b1cf215afb8d02309e00bb3)
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$
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 
121 These routines look for SYN, ACK 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_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 
154 static void
155 TcpMonitorOut(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 
186 These routines handle protocol specific details of packet aliasing.
187 One may observe a certain amount of repetitive arithmetic in these
188 functions, the purpose of which is to compute a revised checksum
189 without actually summing over the entire data packet, which could be
190 unnecessarily time consuming.
191 
192 The purpose of the packet aliasing routines is to replace the source
193 address of the outgoing packet and then correctly put it back for
194 any incoming packets.  For TCP and UDP, ports are also re-mapped.
195 
196 For ICMP echo/timestamp requests and replies, the following scheme
197 is used: the id number is replaced by an alias for the outgoing
198 packet.
199 
200 ICMP error messages are handled by looking at the IP fragment
201 in the data section of the message.
202 
203 For TCP and UDP protocols, a port number is chosen for an outgoing
204 packet, and then incoming packets are identified by IP address and
205 port numbers.  For TCP packets, there is additional logic in the event
206 that sequence and ack numbers have been altered (as is the case for
207 FTP data port commands).
208 
209 The port numbers used by the packet aliasing module are not true
210 ports in the Unix sense.  No sockets are actually bound to ports.
211 They are more correctly thought of as placeholders.
212 
213 All packets go through the aliasing mechanism, whether they come from
214 the gateway machine or other machines on a local area network.
215 */
216 
217 
218 /* Local prototypes */
219 static int IcmpAliasIn1(struct ip *);
220 static int IcmpAliasIn2(struct ip *);
221 static int IcmpAliasIn3(struct ip *);
222 static int IcmpAliasIn (struct ip *);
223 
224 static int IcmpAliasOut1(struct ip *);
225 static int IcmpAliasOut2(struct ip *);
226 static int IcmpAliasOut3(struct ip *);
227 static int IcmpAliasOut (struct ip *);
228 
229 static int UdpAliasOut(struct ip *);
230 static int UdpAliasIn (struct ip *);
231 
232 static int TcpAliasOut(struct ip *, int);
233 static int TcpAliasIn (struct ip *);
234 
235 
236 static int
237 IcmpAliasIn1(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 
281 static int
282 IcmpAliasIn2(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
348 fragment 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 
390 static int
391 IcmpAliasIn3(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 
406 static int
407 IcmpAliasIn(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 
443 static int
444 IcmpAliasOut1(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 
489 static int
490 IcmpAliasOut2(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 
523 static int
524 IcmpAliasOut3(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 
544 static int
545 IcmpAliasOut(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 
581 static int
582 PptpAliasIn(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 
608 static int
609 PptpAliasOut(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 
636 static int
637 UdpAliasIn(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 
716 static int
717 UdpAliasOut(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 
792 static int
793 TcpAliasIn(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 
899 static int
900 TcpAliasOut(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 
1041 The packet aliasing module has a limited ability for handling IP
1042 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1043 received, then the id number of the IP packet is saved, and other
1044 fragments are identified according to their ID number and IP address
1045 they were sent from.  Pointers to unresolved fragments can also be
1046 saved and recalled when a header fragment is seen.
1047 */
1048 
1049 /* Local prototypes */
1050 static int FragmentIn(struct ip *);
1051 static int FragmentOut(struct ip *);
1052 
1053 
1054 static int
1055 FragmentIn(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 
1077 static int
1078 FragmentOut(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 
1109 int
1110 PacketAliasSaveFragment(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 
1128 char *
1129 PacketAliasGetFragment(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 
1152 void
1153 PacketAliasFragmentIn(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 
1173 int
1174 PacketAliasIn(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 
1258 int
1259 PacketAliasOut(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