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