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