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