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