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