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