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