]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias.c
This commit was generated by cvs2svn to compensate for changes in r164219,
[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 #ifdef _KERNEL
115 #include <sys/param.h>
116 #else
117 #include <sys/types.h>
118 #include <stdlib.h>
119 #include <stdio.h>
120 #include <dlfcn.h>
121 #include <errno.h>
122 #include <string.h>
123 #endif
124
125 #include <netinet/in_systm.h>
126 #include <netinet/in.h>
127 #include <netinet/ip.h>
128 #include <netinet/ip_icmp.h>
129 #include <netinet/tcp.h>
130 #include <netinet/udp.h>
131
132 #ifdef _KERNEL
133 #include <netinet/libalias/alias.h>
134 #include <netinet/libalias/alias_local.h>
135 #include <netinet/libalias/alias_mod.h>
136 #else
137 #include <err.h>
138 #include "alias.h"
139 #include "alias_local.h"
140 #include "alias_mod.h"
141 #endif
142
143 static __inline int
144 twowords(void *p)
145 {
146         uint8_t *c = p;
147
148 #if BYTE_ORDER == LITTLE_ENDIAN
149         uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
150         uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
151 #else
152         uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
153         uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
154 #endif
155         return (s1 + s2);
156 }
157
158 /* TCP Handling Routines
159
160     TcpMonitorIn()  -- These routines monitor TCP connections, and
161     TcpMonitorOut()    delete a link when a connection is closed.
162
163 These routines look for SYN, FIN and RST flags to determine when TCP
164 connections open and close.  When a TCP connection closes, the data
165 structure containing packet aliasing information is deleted after
166 a timeout period.
167 */
168
169 /* Local prototypes */
170 static void     TcpMonitorIn(struct ip *, struct alias_link *);
171
172 static void     TcpMonitorOut(struct ip *, struct alias_link *);
173
174
175 static void
176 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
177 {
178         struct tcphdr *tc;
179
180         tc = (struct tcphdr *)ip_next(pip);
181
182         switch (GetStateIn(lnk)) {
183         case ALIAS_TCP_STATE_NOT_CONNECTED:
184                 if (tc->th_flags & TH_RST)
185                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
186                 else if (tc->th_flags & TH_SYN)
187                         SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
188                 break;
189         case ALIAS_TCP_STATE_CONNECTED:
190                 if (tc->th_flags & (TH_FIN | TH_RST))
191                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
192                 break;
193         }
194 }
195
196 static void
197 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
198 {
199         struct tcphdr *tc;
200
201         tc = (struct tcphdr *)ip_next(pip);
202
203         switch (GetStateOut(lnk)) {
204         case ALIAS_TCP_STATE_NOT_CONNECTED:
205                 if (tc->th_flags & TH_RST)
206                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
207                 else if (tc->th_flags & TH_SYN)
208                         SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
209                 break;
210         case ALIAS_TCP_STATE_CONNECTED:
211                 if (tc->th_flags & (TH_FIN | TH_RST))
212                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
213                 break;
214         }
215 }
216
217
218
219
220
221 /* Protocol Specific Packet Aliasing Routines
222
223     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
224     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
225     ProtoAliasIn(), ProtoAliasOut()
226     UdpAliasIn(), UdpAliasOut()
227     TcpAliasIn(), TcpAliasOut()
228
229 These routines handle protocol specific details of packet aliasing.
230 One may observe a certain amount of repetitive arithmetic in these
231 functions, the purpose of which is to compute a revised checksum
232 without actually summing over the entire data packet, which could be
233 unnecessarily time consuming.
234
235 The purpose of the packet aliasing routines is to replace the source
236 address of the outgoing packet and then correctly put it back for
237 any incoming packets.  For TCP and UDP, ports are also re-mapped.
238
239 For ICMP echo/timestamp requests and replies, the following scheme
240 is used: the ID number is replaced by an alias for the outgoing
241 packet.
242
243 ICMP error messages are handled by looking at the IP fragment
244 in the data section of the message.
245
246 For TCP and UDP protocols, a port number is chosen for an outgoing
247 packet, and then incoming packets are identified by IP address and
248 port numbers.  For TCP packets, there is additional logic in the event
249 that sequence and ACK numbers have been altered (as in the case for
250 FTP data port commands).
251
252 The port numbers used by the packet aliasing module are not true
253 ports in the Unix sense.  No sockets are actually bound to ports.
254 They are more correctly thought of as placeholders.
255
256 All packets go through the aliasing mechanism, whether they come from
257 the gateway machine or other machines on a local area network.
258 */
259
260
261 /* Local prototypes */
262 static int      IcmpAliasIn1(struct libalias *, struct ip *);
263 static int      IcmpAliasIn2(struct libalias *, struct ip *);
264 static int      IcmpAliasIn(struct libalias *, struct ip *);
265
266 static int      IcmpAliasOut1(struct libalias *, struct ip *, int create);
267 static int      IcmpAliasOut2(struct libalias *, struct ip *);
268 static int      IcmpAliasOut(struct libalias *, struct ip *, int create);
269
270 static int      ProtoAliasIn(struct libalias *, struct ip *);
271 static int      ProtoAliasOut(struct libalias *, struct ip *, int create);
272
273 static int      UdpAliasIn(struct libalias *, struct ip *);
274 static int      UdpAliasOut(struct libalias *, struct ip *, int create);
275
276 static int      TcpAliasIn(struct libalias *, struct ip *);
277 static int      TcpAliasOut(struct libalias *, struct ip *, int, int create);
278
279
280 static int
281 IcmpAliasIn1(struct libalias *la, struct ip *pip)
282 {
283 /*
284     De-alias incoming echo and timestamp replies.
285     Alias incoming echo and timestamp requests.
286 */
287         struct alias_link *lnk;
288         struct icmp *ic;
289
290         ic = (struct icmp *)ip_next(pip);
291
292 /* Get source address from ICMP data field and restore original data */
293         lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
294         if (lnk != NULL) {
295                 u_short original_id;
296                 int accumulate;
297
298                 original_id = GetOriginalPort(lnk);
299
300 /* Adjust ICMP checksum */
301                 accumulate = ic->icmp_id;
302                 accumulate -= original_id;
303                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
304
305 /* Put original sequence number back in */
306                 ic->icmp_id = original_id;
307
308 /* Put original address back into IP header */
309                 {
310                         struct in_addr original_address;
311
312                         original_address = GetOriginalAddress(lnk);
313                         DifferentialChecksum(&pip->ip_sum,
314                             &original_address, &pip->ip_dst, 2);
315                         pip->ip_dst = original_address;
316                 }
317
318                 return (PKT_ALIAS_OK);
319         }
320         return (PKT_ALIAS_IGNORED);
321 }
322
323 static int
324 IcmpAliasIn2(struct libalias *la, struct ip *pip)
325 {
326 /*
327     Alias incoming ICMP error messages containing
328     IP header and first 64 bits of datagram.
329 */
330         struct ip *ip;
331         struct icmp *ic, *ic2;
332         struct udphdr *ud;
333         struct tcphdr *tc;
334         struct alias_link *lnk;
335
336         ic = (struct icmp *)ip_next(pip);
337         ip = &ic->icmp_ip;
338
339         ud = (struct udphdr *)ip_next(ip);
340         tc = (struct tcphdr *)ip_next(ip);
341         ic2 = (struct icmp *)ip_next(ip);
342
343         if (ip->ip_p == IPPROTO_UDP)
344                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
345                     ud->uh_dport, ud->uh_sport,
346                     IPPROTO_UDP, 0);
347         else if (ip->ip_p == IPPROTO_TCP)
348                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
349                     tc->th_dport, tc->th_sport,
350                     IPPROTO_TCP, 0);
351         else if (ip->ip_p == IPPROTO_ICMP) {
352                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
353                         lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
354                 else
355                         lnk = NULL;
356         } else
357                 lnk = NULL;
358
359         if (lnk != NULL) {
360                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
361                         int accumulate, accumulate2;
362                         struct in_addr original_address;
363                         u_short original_port;
364
365                         original_address = GetOriginalAddress(lnk);
366                         original_port = GetOriginalPort(lnk);
367
368 /* Adjust ICMP checksum */
369                         accumulate = twowords(&ip->ip_src);
370                         accumulate -= twowords(&original_address);
371                         accumulate += ud->uh_sport;
372                         accumulate -= original_port;
373                         accumulate2 = accumulate;
374                         accumulate2 += ip->ip_sum;
375                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
376                         accumulate2 -= ip->ip_sum;
377                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
378
379 /* Un-alias address in IP header */
380                         DifferentialChecksum(&pip->ip_sum,
381                             &original_address, &pip->ip_dst, 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                 } else if (ip->ip_p == IPPROTO_ICMP) {
389                         int accumulate, accumulate2;
390                         struct in_addr original_address;
391                         u_short original_id;
392
393                         original_address = GetOriginalAddress(lnk);
394                         original_id = GetOriginalPort(lnk);
395
396 /* Adjust ICMP checksum */
397                         accumulate = twowords(&ip->ip_src);
398                         accumulate -= twowords(&original_address);
399                         accumulate += ic2->icmp_id;
400                         accumulate -= original_id;
401                         accumulate2 = accumulate;
402                         accumulate2 += ip->ip_sum;
403                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
404                         accumulate2 -= ip->ip_sum;
405                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
406
407 /* Un-alias address in IP header */
408                         DifferentialChecksum(&pip->ip_sum,
409                             &original_address, &pip->ip_dst, 2);
410                         pip->ip_dst = original_address;
411
412 /* Un-alias address of original IP packet and sequence number of
413    embedded ICMP datagram */
414                         ip->ip_src = original_address;
415                         ic2->icmp_id = original_id;
416                 }
417                 return (PKT_ALIAS_OK);
418         }
419         return (PKT_ALIAS_IGNORED);
420 }
421
422
423 static int
424 IcmpAliasIn(struct libalias *la, struct ip *pip)
425 {
426         int iresult;
427         struct icmp *ic;
428
429 /* Return if proxy-only mode is enabled */
430         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
431                 return (PKT_ALIAS_OK);
432
433         ic = (struct icmp *)ip_next(pip);
434
435         iresult = PKT_ALIAS_IGNORED;
436         switch (ic->icmp_type) {
437         case ICMP_ECHOREPLY:
438         case ICMP_TSTAMPREPLY:
439                 if (ic->icmp_code == 0) {
440                         iresult = IcmpAliasIn1(la, pip);
441                 }
442                 break;
443         case ICMP_UNREACH:
444         case ICMP_SOURCEQUENCH:
445         case ICMP_TIMXCEED:
446         case ICMP_PARAMPROB:
447                 iresult = IcmpAliasIn2(la, pip);
448                 break;
449         case ICMP_ECHO:
450         case ICMP_TSTAMP:
451                 iresult = IcmpAliasIn1(la, pip);
452                 break;
453         }
454         return (iresult);
455 }
456
457
458 static int
459 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
460 {
461 /*
462     Alias outgoing echo and timestamp requests.
463     De-alias outgoing echo and timestamp replies.
464 */
465         struct alias_link *lnk;
466         struct icmp *ic;
467
468         ic = (struct icmp *)ip_next(pip);
469
470 /* Save overwritten data for when echo packet returns */
471         lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
472         if (lnk != NULL) {
473                 u_short alias_id;
474                 int accumulate;
475
476                 alias_id = GetAliasPort(lnk);
477
478 /* Since data field is being modified, adjust ICMP checksum */
479                 accumulate = ic->icmp_id;
480                 accumulate -= alias_id;
481                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
482
483 /* Alias sequence number */
484                 ic->icmp_id = alias_id;
485
486 /* Change source address */
487                 {
488                         struct in_addr alias_address;
489
490                         alias_address = GetAliasAddress(lnk);
491                         DifferentialChecksum(&pip->ip_sum,
492                             &alias_address, &pip->ip_src, 2);
493                         pip->ip_src = alias_address;
494                 }
495
496                 return (PKT_ALIAS_OK);
497         }
498         return (PKT_ALIAS_IGNORED);
499 }
500
501
502 static int
503 IcmpAliasOut2(struct libalias *la, struct ip *pip)
504 {
505 /*
506     Alias outgoing ICMP error messages containing
507     IP header and first 64 bits of datagram.
508 */
509         struct ip *ip;
510         struct icmp *ic, *ic2;
511         struct udphdr *ud;
512         struct tcphdr *tc;
513         struct alias_link *lnk;
514
515         ic = (struct icmp *)ip_next(pip);
516         ip = &ic->icmp_ip;
517
518         ud = (struct udphdr *)ip_next(ip);
519         tc = (struct tcphdr *)ip_next(ip);
520         ic2 = (struct icmp *)ip_next(ip);
521
522         if (ip->ip_p == IPPROTO_UDP)
523                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
524                     ud->uh_dport, ud->uh_sport,
525                     IPPROTO_UDP, 0);
526         else if (ip->ip_p == IPPROTO_TCP)
527                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
528                     tc->th_dport, tc->th_sport,
529                     IPPROTO_TCP, 0);
530         else if (ip->ip_p == IPPROTO_ICMP) {
531                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
532                         lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
533                 else
534                         lnk = NULL;
535         } else
536                 lnk = NULL;
537
538         if (lnk != NULL) {
539                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
540                         int accumulate;
541                         struct in_addr alias_address;
542                         u_short alias_port;
543
544                         alias_address = GetAliasAddress(lnk);
545                         alias_port = GetAliasPort(lnk);
546
547 /* Adjust ICMP checksum */
548                         accumulate = twowords(&ip->ip_dst);
549                         accumulate -= twowords(&alias_address);
550                         accumulate += ud->uh_dport;
551                         accumulate -= alias_port;
552                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
553
554 /*
555  * Alias address in IP header if it comes from the host
556  * the original TCP/UDP packet was destined for.
557  */
558                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
559                                 DifferentialChecksum(&pip->ip_sum,
560                                     &alias_address, &pip->ip_src, 2);
561                                 pip->ip_src = alias_address;
562                         }
563 /* Alias address and port number of original IP packet
564 fragment contained in ICMP data section */
565                         ip->ip_dst = alias_address;
566                         ud->uh_dport = alias_port;
567                 } else if (ip->ip_p == IPPROTO_ICMP) {
568                         int accumulate;
569                         struct in_addr alias_address;
570                         u_short alias_id;
571
572                         alias_address = GetAliasAddress(lnk);
573                         alias_id = GetAliasPort(lnk);
574
575 /* Adjust ICMP checksum */
576                         accumulate = twowords(&ip->ip_dst);
577                         accumulate -= twowords(&alias_address);
578                         accumulate += ic2->icmp_id;
579                         accumulate -= alias_id;
580                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
581
582 /*
583  * Alias address in IP header if it comes from the host
584  * the original ICMP message was destined for.
585  */
586                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
587                                 DifferentialChecksum(&pip->ip_sum,
588                                     &alias_address, &pip->ip_src, 2);
589                                 pip->ip_src = alias_address;
590                         }
591 /* Alias address of original IP packet and sequence number of
592    embedded ICMP datagram */
593                         ip->ip_dst = alias_address;
594                         ic2->icmp_id = alias_id;
595                 }
596                 return (PKT_ALIAS_OK);
597         }
598         return (PKT_ALIAS_IGNORED);
599 }
600
601
602 static int
603 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
604 {
605         int iresult;
606         struct icmp *ic;
607
608         (void)create;
609
610 /* Return if proxy-only mode is enabled */
611         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
612                 return (PKT_ALIAS_OK);
613
614         ic = (struct icmp *)ip_next(pip);
615
616         iresult = PKT_ALIAS_IGNORED;
617         switch (ic->icmp_type) {
618         case ICMP_ECHO:
619         case ICMP_TSTAMP:
620                 if (ic->icmp_code == 0) {
621                         iresult = IcmpAliasOut1(la, pip, create);
622                 }
623                 break;
624         case ICMP_UNREACH:
625         case ICMP_SOURCEQUENCH:
626         case ICMP_TIMXCEED:
627         case ICMP_PARAMPROB:
628                 iresult = IcmpAliasOut2(la, pip);
629                 break;
630         case ICMP_ECHOREPLY:
631         case ICMP_TSTAMPREPLY:
632                 iresult = IcmpAliasOut1(la, pip, create);
633         }
634         return (iresult);
635 }
636
637
638
639 static int
640 ProtoAliasIn(struct libalias *la, struct ip *pip)
641 {
642 /*
643   Handle incoming IP packets. The
644   only thing which is done in this case is to alias
645   the dest IP address of the packet to our inside
646   machine.
647 */
648         struct alias_link *lnk;
649
650 /* Return if proxy-only mode is enabled */
651         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
652                 return (PKT_ALIAS_OK);
653
654         lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
655         if (lnk != NULL) {
656                 struct in_addr original_address;
657
658                 original_address = GetOriginalAddress(lnk);
659
660 /* Restore original IP address */
661                 DifferentialChecksum(&pip->ip_sum,
662                     &original_address, &pip->ip_dst, 2);
663                 pip->ip_dst = original_address;
664
665                 return (PKT_ALIAS_OK);
666         }
667         return (PKT_ALIAS_IGNORED);
668 }
669
670
671 static int
672 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
673 {
674 /*
675   Handle outgoing IP packets. The
676   only thing which is done in this case is to alias
677   the source IP address of the packet.
678 */
679         struct alias_link *lnk;
680
681         (void)create;
682
683 /* Return if proxy-only mode is enabled */
684         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
685                 return (PKT_ALIAS_OK);
686
687         lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
688         if (lnk != NULL) {
689                 struct in_addr alias_address;
690
691                 alias_address = GetAliasAddress(lnk);
692
693 /* Change source address */
694                 DifferentialChecksum(&pip->ip_sum,
695                     &alias_address, &pip->ip_src, 2);
696                 pip->ip_src = alias_address;
697
698                 return (PKT_ALIAS_OK);
699         }
700         return (PKT_ALIAS_IGNORED);
701 }
702
703
704 static int
705 UdpAliasIn(struct libalias *la, struct ip *pip)
706 {
707         struct udphdr *ud;
708         struct alias_link *lnk;
709
710 /* Return if proxy-only mode is enabled */
711         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
712                 return (PKT_ALIAS_OK);
713
714         ud = (struct udphdr *)ip_next(pip);
715
716         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
717             ud->uh_sport, ud->uh_dport,
718             IPPROTO_UDP, 1);
719         if (lnk != NULL) {
720                 struct in_addr alias_address;
721                 struct in_addr original_address;
722                 u_short alias_port;
723                 int accumulate;
724                 int r = 0, error;
725                 struct alias_data ad = {
726                         .lnk = lnk, 
727                         .oaddr = &original_address, 
728                         .aaddr = &alias_address,
729                         .aport = &alias_port,
730                         .sport = &ud->uh_sport,
731                         .dport = &ud->uh_dport,
732                         .maxpktsize = 0
733                 };
734
735                 alias_address = GetAliasAddress(lnk);
736                 original_address = GetOriginalAddress(lnk);
737                 alias_port = ud->uh_dport;
738                 ud->uh_dport = GetOriginalPort(lnk);
739
740                 /* Walk out chain. */           
741                 error = find_handler(IN, UDP, la, pip, &ad);
742
743 /* If UDP checksum is not zero, then adjust since destination port */
744 /* is being unaliased and destination address is being altered.    */
745                 if (ud->uh_sum != 0) {
746                         accumulate = alias_port;
747                         accumulate -= ud->uh_dport;
748                         accumulate += twowords(&alias_address);
749                         accumulate -= twowords(&original_address);
750                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
751                 }
752 /* Restore original IP address */
753                 DifferentialChecksum(&pip->ip_sum,
754                     &original_address, &pip->ip_dst, 2);
755                 pip->ip_dst = original_address;
756
757                 /*
758                  * If we cannot figure out the packet, ignore it.
759                  */
760                 if (r < 0)
761                         return (PKT_ALIAS_IGNORED);
762                 else
763                         return (PKT_ALIAS_OK);
764         }
765         return (PKT_ALIAS_IGNORED);
766 }
767
768 static int
769 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
770 {
771         struct udphdr *ud;
772         struct alias_link *lnk;
773         int error;
774
775 /* Return if proxy-only mode is enabled */
776         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
777                 return (PKT_ALIAS_OK);
778
779         ud = (struct udphdr *)ip_next(pip);
780
781         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
782             ud->uh_sport, ud->uh_dport,
783             IPPROTO_UDP, create);
784         if (lnk != NULL) {
785                 u_short alias_port;
786                 struct in_addr alias_address;
787                 struct alias_data ad = {
788                         .lnk = lnk, 
789                         .oaddr = NULL,
790                         .aaddr = &alias_address,
791                         .aport = &alias_port,
792                         .sport = &ud->uh_sport,
793                         .dport = &ud->uh_dport,
794                         .maxpktsize = 0
795                 };
796
797                 alias_address = GetAliasAddress(lnk);
798                 alias_port = GetAliasPort(lnk);
799
800                 /* Walk out chain. */           
801                 error = find_handler(OUT, UDP, la, pip, &ad);
802
803 /* If UDP checksum is not zero, adjust since source port is */
804 /* being aliased and source address is being altered        */
805                 if (ud->uh_sum != 0) {
806                         int accumulate;
807
808                         accumulate = ud->uh_sport;
809                         accumulate -= alias_port;
810                         accumulate += twowords(&pip->ip_src);
811                         accumulate -= twowords(&alias_address);
812                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
813                 }
814 /* Put alias port in UDP header */
815                 ud->uh_sport = alias_port;
816
817 /* Change source address */
818                 DifferentialChecksum(&pip->ip_sum,
819                     &alias_address, &pip->ip_src, 2);
820                 pip->ip_src = alias_address;
821
822                 return (PKT_ALIAS_OK);
823         }
824         return (PKT_ALIAS_IGNORED);
825 }
826
827
828
829 static int
830 TcpAliasIn(struct libalias *la, struct ip *pip)
831 {
832         struct tcphdr *tc;
833         struct alias_link *lnk;
834
835         tc = (struct tcphdr *)ip_next(pip);
836
837         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
838             tc->th_sport, tc->th_dport,
839             IPPROTO_TCP,
840             !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
841         if (lnk != NULL) {
842                 struct in_addr alias_address;
843                 struct in_addr original_address;
844                 struct in_addr proxy_address;
845                 u_short alias_port;
846                 u_short proxy_port;
847                 int accumulate, error;
848
849                 /* 
850                  * The init of MANY vars is a bit below, but aliashandlepptpin 
851                  * seems to need the destination port that came within the
852                  * packet and not the original one looks below [*].
853                  */
854
855                 struct alias_data ad = {
856                         .lnk = lnk, 
857                         .oaddr = NULL,
858                         .aaddr = NULL,
859                         .aport = NULL,
860                         .sport = &tc->th_sport,
861                         .dport = &tc->th_dport,
862                         .maxpktsize = 0
863                 };
864
865                 /* Walk out chain. */           
866                 error = find_handler(IN, TCP, la, pip, &ad);
867
868                 alias_address = GetAliasAddress(lnk);
869                 original_address = GetOriginalAddress(lnk);
870                 proxy_address = GetProxyAddress(lnk);
871                 alias_port = tc->th_dport;
872                 tc->th_dport = GetOriginalPort(lnk);
873                 proxy_port = GetProxyPort(lnk);
874
875                 /* 
876                  * Look above, if anyone is going to add find_handler AFTER 
877                  * this aliashandlepptpin/point, please redo alias_data too.
878                  * Uncommenting the piece here below should be enough.
879                  */
880 #if 0
881                                  struct alias_data ad = {
882                                         .lnk = lnk,
883                                         .oaddr = &original_address,
884                                         .aaddr = &alias_address,
885                                         .aport = &alias_port,
886                                         .sport = &ud->uh_sport,
887                                         .dport = &ud->uh_dport,
888                                         .maxpktsize = 0
889                                 };
890                 
891                                 /* Walk out chain. */
892                                 error = find_handler(la, pip, &ad);
893                                 if (error == EHDNOF)
894                                         printf("Protocol handler not found\n");
895 #endif
896
897 /* Adjust TCP checksum since destination port is being unaliased */
898 /* and destination port is being altered.                        */
899                 accumulate = alias_port;
900                 accumulate -= tc->th_dport;
901                 accumulate += twowords(&alias_address);
902                 accumulate -= twowords(&original_address);
903
904 /* If this is a proxy, then modify the TCP source port and
905    checksum accumulation */
906                 if (proxy_port != 0) {
907                         accumulate += tc->th_sport;
908                         tc->th_sport = proxy_port;
909                         accumulate -= tc->th_sport;
910                         accumulate += twowords(&pip->ip_src);
911                         accumulate -= twowords(&proxy_address);
912                 }
913 /* See if ACK number needs to be modified */
914                 if (GetAckModified(lnk) == 1) {
915                         int delta;
916
917                         delta = GetDeltaAckIn(pip, lnk);
918                         if (delta != 0) {
919                                 accumulate += twowords(&tc->th_ack);
920                                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
921                                 accumulate -= twowords(&tc->th_ack);
922                         }
923                 }
924                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
925
926 /* Restore original IP address */
927                 accumulate = twowords(&pip->ip_dst);
928                 pip->ip_dst = original_address;
929                 accumulate -= twowords(&pip->ip_dst);
930
931 /* If this is a transparent proxy packet, then modify the source
932    address */
933                 if (proxy_address.s_addr != 0) {
934                         accumulate += twowords(&pip->ip_src);
935                         pip->ip_src = proxy_address;
936                         accumulate -= twowords(&pip->ip_src);
937                 }
938                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
939
940 /* Monitor TCP connection state */
941                 TcpMonitorIn(pip, lnk);
942
943                 return (PKT_ALIAS_OK);
944         }
945         return (PKT_ALIAS_IGNORED);
946 }
947
948 static int
949 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
950 {
951         int proxy_type, error;
952         u_short dest_port;
953         u_short proxy_server_port;
954         struct in_addr dest_address;
955         struct in_addr proxy_server_address;
956         struct tcphdr *tc;
957         struct alias_link *lnk;
958
959         tc = (struct tcphdr *)ip_next(pip);
960
961         if (create)
962                 proxy_type =
963                     ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
964         else
965                 proxy_type = 0;
966
967         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
968                 return (PKT_ALIAS_OK);
969
970 /* If this is a transparent proxy, save original destination,
971    then alter the destination and adjust checksums */
972         dest_port = tc->th_dport;
973         dest_address = pip->ip_dst;
974         if (proxy_type != 0) {
975                 int accumulate;
976
977                 accumulate = tc->th_dport;
978                 tc->th_dport = proxy_server_port;
979                 accumulate -= tc->th_dport;
980                 accumulate += twowords(&pip->ip_dst);
981                 accumulate -= twowords(&proxy_server_address);
982                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
983
984                 accumulate = twowords(&pip->ip_dst);
985                 pip->ip_dst = proxy_server_address;
986                 accumulate -= twowords(&pip->ip_dst);
987                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
988         }
989         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
990             tc->th_sport, tc->th_dport,
991             IPPROTO_TCP, create);
992         if (lnk == NULL)
993                 return (PKT_ALIAS_IGNORED);
994         if (lnk != NULL) {
995                 u_short alias_port;
996                 struct in_addr alias_address;
997                 int accumulate;
998                 struct alias_data ad = {
999                         .lnk = lnk, 
1000                         .oaddr = NULL,
1001                         .aaddr = &alias_address,
1002                         .aport = &alias_port,
1003                         .sport = &tc->th_sport,
1004                         .dport = &tc->th_dport,
1005                         .maxpktsize = maxpacketsize
1006                 };
1007
1008 /* Save original destination address, if this is a proxy packet.
1009    Also modify packet to include destination encoding.  This may
1010    change the size of IP header. */
1011                 if (proxy_type != 0) {
1012                         SetProxyPort(lnk, dest_port);
1013                         SetProxyAddress(lnk, dest_address);
1014                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1015                         tc = (struct tcphdr *)ip_next(pip);
1016                 }
1017 /* Get alias address and port */
1018                 alias_port = GetAliasPort(lnk);
1019                 alias_address = GetAliasAddress(lnk);
1020
1021 /* Monitor TCP connection state */
1022                 TcpMonitorOut(pip, lnk);
1023                 
1024                 /* Walk out chain. */           
1025                 error = find_handler(OUT, TCP, la, pip, &ad);
1026
1027 /* Adjust TCP checksum since source port is being aliased */
1028 /* and source address is being altered                    */
1029                 accumulate = tc->th_sport;
1030                 tc->th_sport = alias_port;
1031                 accumulate -= tc->th_sport;
1032                 accumulate += twowords(&pip->ip_src);
1033                 accumulate -= twowords(&alias_address);
1034
1035 /* Modify sequence number if necessary */
1036                 if (GetAckModified(lnk) == 1) {
1037                         int delta;
1038
1039                         delta = GetDeltaSeqOut(pip, lnk);
1040                         if (delta != 0) {
1041                                 accumulate += twowords(&tc->th_seq);
1042                                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1043                                 accumulate -= twowords(&tc->th_seq);
1044                         }
1045                 }
1046                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1047
1048 /* Change source address */
1049                 accumulate = twowords(&pip->ip_src);
1050                 pip->ip_src = alias_address;
1051                 accumulate -= twowords(&pip->ip_src);
1052                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1053
1054                 return (PKT_ALIAS_OK);
1055         }
1056         return (PKT_ALIAS_IGNORED);
1057 }
1058
1059
1060
1061
1062 /* Fragment Handling
1063
1064     FragmentIn()
1065     FragmentOut()
1066
1067 The packet aliasing module has a limited ability for handling IP
1068 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1069 received, then the ID number of the IP packet is saved, and other
1070 fragments are identified according to their ID number and IP address
1071 they were sent from.  Pointers to unresolved fragments can also be
1072 saved and recalled when a header fragment is seen.
1073 */
1074
1075 /* Local prototypes */
1076 static int      FragmentIn(struct libalias *, struct ip *);
1077 static int      FragmentOut(struct libalias *, struct ip *);
1078
1079
1080 static int
1081 FragmentIn(struct libalias *la, struct ip *pip)
1082 {
1083         struct alias_link *lnk;
1084
1085         lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1086         if (lnk != NULL) {
1087                 struct in_addr original_address;
1088
1089                 GetFragmentAddr(lnk, &original_address);
1090                 DifferentialChecksum(&pip->ip_sum,
1091                     &original_address, &pip->ip_dst, 2);
1092                 pip->ip_dst = original_address;
1093
1094                 return (PKT_ALIAS_OK);
1095         }
1096         return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1097 }
1098
1099
1100 static int
1101 FragmentOut(struct libalias *la, struct ip *pip)
1102 {
1103         struct in_addr alias_address;
1104
1105         alias_address = FindAliasAddress(la, pip->ip_src);
1106         DifferentialChecksum(&pip->ip_sum,
1107             &alias_address, &pip->ip_src, 2);
1108         pip->ip_src = alias_address;
1109
1110         return (PKT_ALIAS_OK);
1111 }
1112
1113
1114
1115
1116
1117
1118 /* Outside World Access
1119
1120         PacketAliasSaveFragment()
1121         PacketAliasGetFragment()
1122         PacketAliasFragmentIn()
1123         PacketAliasIn()
1124         PacketAliasOut()
1125         PacketUnaliasOut()
1126
1127 (prototypes in alias.h)
1128 */
1129
1130
1131 int
1132 LibAliasSaveFragment(struct libalias *la, char *ptr)
1133 {
1134         int iresult;
1135         struct alias_link *lnk;
1136         struct ip *pip;
1137
1138         pip = (struct ip *)ptr;
1139         lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1140         iresult = PKT_ALIAS_ERROR;
1141         if (lnk != NULL) {
1142                 SetFragmentPtr(lnk, ptr);
1143                 iresult = PKT_ALIAS_OK;
1144         }
1145         return (iresult);
1146 }
1147
1148
1149 char           *
1150 LibAliasGetFragment(struct libalias *la, char *ptr)
1151 {
1152         struct alias_link *lnk;
1153         char *fptr;
1154         struct ip *pip;
1155
1156         pip = (struct ip *)ptr;
1157         lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1158         if (lnk != NULL) {
1159                 GetFragmentPtr(lnk, &fptr);
1160                 SetFragmentPtr(lnk, NULL);
1161                 SetExpire(lnk, 0);      /* Deletes link */
1162
1163                 return (fptr);
1164         } else {
1165                 return (NULL);
1166         }
1167 }
1168
1169
1170 void
1171 LibAliasFragmentIn(struct libalias *la, char *ptr,      /* Points to correctly
1172                                                          * de-aliased header
1173                                                          * fragment */
1174     char *ptr_fragment          /* Points to fragment which must be
1175                                  * de-aliased   */
1176 )
1177 {
1178         struct ip *pip;
1179         struct ip *fpip;
1180
1181         (void)la;
1182         pip = (struct ip *)ptr;
1183         fpip = (struct ip *)ptr_fragment;
1184
1185         DifferentialChecksum(&fpip->ip_sum,
1186             &pip->ip_dst, &fpip->ip_dst, 2);
1187         fpip->ip_dst = pip->ip_dst;
1188 }
1189
1190
1191 int
1192 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1193 {
1194         struct in_addr alias_addr;
1195         struct ip *pip;
1196         int iresult;
1197
1198         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1199                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1200                 iresult = LibAliasOut(la, ptr, maxpacketsize);
1201                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1202                 return (iresult);
1203         }
1204         HouseKeeping(la);
1205         ClearCheckNewLink(la);
1206         pip = (struct ip *)ptr;
1207         alias_addr = pip->ip_dst;
1208
1209         /* Defense against mangled packets */
1210         if (ntohs(pip->ip_len) > maxpacketsize
1211             || (pip->ip_hl << 2) > maxpacketsize)
1212                 return (PKT_ALIAS_IGNORED);
1213
1214         iresult = PKT_ALIAS_IGNORED;
1215         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1216                 switch (pip->ip_p) {
1217                 case IPPROTO_ICMP:
1218                         iresult = IcmpAliasIn(la, pip);
1219                         break;
1220                 case IPPROTO_UDP:
1221                         iresult = UdpAliasIn(la, pip);
1222                         break;
1223                 case IPPROTO_TCP:
1224                         iresult = TcpAliasIn(la, pip);
1225                         break;
1226                 case IPPROTO_GRE: {
1227                         int error;
1228                         struct alias_data ad = {
1229                                 .lnk = NULL, 
1230                                 .oaddr = NULL, 
1231                                 .aaddr = NULL,
1232                                 .aport = NULL,
1233                                 .sport = NULL,
1234                                 .dport = NULL,
1235                                 .maxpktsize = 0                  
1236                         };
1237                         
1238                         /* Walk out chain. */           
1239                         error = find_handler(IN, IP, la, pip, &ad);
1240                         if (error ==  0)
1241                                 iresult = PKT_ALIAS_OK;
1242                         else
1243                                 iresult = ProtoAliasIn(la, pip);
1244                 }
1245                         break; 
1246                 default:
1247                         iresult = ProtoAliasIn(la, pip);
1248                         break;
1249                 }
1250
1251                 if (ntohs(pip->ip_off) & IP_MF) {
1252                         struct alias_link *lnk;
1253
1254                         lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1255                         if (lnk != NULL) {
1256                                 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1257                                 SetFragmentAddr(lnk, pip->ip_dst);
1258                         } else {
1259                                 iresult = PKT_ALIAS_ERROR;
1260                         }
1261                 }
1262         } else {
1263                 iresult = FragmentIn(la, pip);
1264         }
1265
1266         return (iresult);
1267 }
1268
1269
1270
1271 /* Unregistered address ranges */
1272
1273 /* 10.0.0.0   ->   10.255.255.255 */
1274 #define UNREG_ADDR_A_LOWER 0x0a000000
1275 #define UNREG_ADDR_A_UPPER 0x0affffff
1276
1277 /* 172.16.0.0  ->  172.31.255.255 */
1278 #define UNREG_ADDR_B_LOWER 0xac100000
1279 #define UNREG_ADDR_B_UPPER 0xac1fffff
1280
1281 /* 192.168.0.0 -> 192.168.255.255 */
1282 #define UNREG_ADDR_C_LOWER 0xc0a80000
1283 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1284
1285 int
1286 LibAliasOut(struct libalias *la, char *ptr,     /* valid IP packet */
1287     int maxpacketsize           /* How much the packet data may grow (FTP
1288                                  * and IRC inline changes) */
1289 )
1290 {
1291         return (LibAliasOutTry(la, ptr, maxpacketsize, 1));
1292 }
1293
1294 int
1295 LibAliasOutTry(struct libalias *la, char *ptr,  /* valid IP packet */
1296     int maxpacketsize,          /* How much the packet data may grow (FTP
1297                                  * and IRC inline changes) */
1298     int create                  /* Create new entries ? */
1299 )
1300 {
1301         int iresult;
1302         struct in_addr addr_save;
1303         struct ip *pip;
1304
1305         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1306                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1307                 iresult = LibAliasIn(la, ptr, maxpacketsize);
1308                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1309                 return (iresult);
1310         }
1311         HouseKeeping(la);
1312         ClearCheckNewLink(la);
1313         pip = (struct ip *)ptr;
1314
1315         /* Defense against mangled packets */
1316         if (ntohs(pip->ip_len) > maxpacketsize
1317             || (pip->ip_hl << 2) > maxpacketsize)
1318                 return (PKT_ALIAS_IGNORED);
1319
1320         addr_save = GetDefaultAliasAddress(la);
1321         if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1322                 u_long addr;
1323                 int iclass;
1324
1325                 iclass = 0;
1326                 addr = ntohl(pip->ip_src.s_addr);
1327                 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1328                         iclass = 3;
1329                 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1330                         iclass = 2;
1331                 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1332                         iclass = 1;
1333
1334                 if (iclass == 0) {
1335                         SetDefaultAliasAddress(la, pip->ip_src);
1336                 }
1337         } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1338                 SetDefaultAliasAddress(la, pip->ip_src);
1339         }
1340         iresult = PKT_ALIAS_IGNORED;
1341         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1342                 switch (pip->ip_p) {
1343                 case IPPROTO_ICMP:
1344                         iresult = IcmpAliasOut(la, pip, create);
1345                         break;
1346                 case IPPROTO_UDP:
1347                         iresult = UdpAliasOut(la, pip, create);
1348                         break;
1349                         case IPPROTO_TCP:
1350                         iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1351                         break;
1352                 case IPPROTO_GRE: {
1353                         int error;
1354                         struct alias_data ad = {
1355                                 .lnk = NULL, 
1356                                 .oaddr = NULL, 
1357                                 .aaddr = NULL,
1358                                 .aport = NULL,
1359                                 .sport = NULL,
1360                                 .dport = NULL,
1361                                 .maxpktsize = 0                  
1362                         };
1363                         /* Walk out chain. */           
1364                         error = find_handler(OUT, IP, la, pip, &ad);
1365                         if (error == 0)
1366                                 iresult = PKT_ALIAS_OK;
1367                         else
1368                                 iresult = ProtoAliasOut(la, pip, create);
1369                 }
1370                         break;
1371                 default:
1372                         iresult = ProtoAliasOut(la, pip, create);
1373                         break;
1374                 }
1375         } else {
1376                 iresult = FragmentOut(la, pip);
1377         }
1378
1379         SetDefaultAliasAddress(la, addr_save);
1380         return (iresult);
1381 }
1382
1383 int
1384 LibAliasUnaliasOut(struct libalias *la, char *ptr,      /* valid IP packet */
1385     int maxpacketsize           /* for error checking */
1386 )
1387 {
1388         struct ip *pip;
1389         struct icmp *ic;
1390         struct udphdr *ud;
1391         struct tcphdr *tc;
1392         struct alias_link *lnk;
1393         int iresult = PKT_ALIAS_IGNORED;
1394
1395         pip = (struct ip *)ptr;
1396
1397         /* Defense against mangled packets */
1398         if (ntohs(pip->ip_len) > maxpacketsize
1399             || (pip->ip_hl << 2) > maxpacketsize)
1400                 return (iresult);
1401
1402         ud = (struct udphdr *)ip_next(pip);
1403         tc = (struct tcphdr *)ip_next(pip);
1404         ic = (struct icmp *)ip_next(pip);
1405
1406         /* Find a link */
1407         if (pip->ip_p == IPPROTO_UDP)
1408                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1409                     ud->uh_dport, ud->uh_sport,
1410                     IPPROTO_UDP, 0);
1411         else if (pip->ip_p == IPPROTO_TCP)
1412                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1413                     tc->th_dport, tc->th_sport,
1414                     IPPROTO_TCP, 0);
1415         else if (pip->ip_p == IPPROTO_ICMP)
1416                 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1417         else
1418                 lnk = NULL;
1419
1420         /* Change it from an aliased packet to an unaliased packet */
1421         if (lnk != NULL) {
1422                 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1423                         int accumulate;
1424                         struct in_addr original_address;
1425                         u_short original_port;
1426
1427                         original_address = GetOriginalAddress(lnk);
1428                         original_port = GetOriginalPort(lnk);
1429
1430                         /* Adjust TCP/UDP checksum */
1431                         accumulate = twowords(&pip->ip_src);
1432                         accumulate -= twowords(&original_address);
1433
1434                         if (pip->ip_p == IPPROTO_UDP) {
1435                                 accumulate += ud->uh_sport;
1436                                 accumulate -= original_port;
1437                                 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1438                         } else {
1439                                 accumulate += tc->th_sport;
1440                                 accumulate -= original_port;
1441                                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1442                         }
1443
1444                         /* Adjust IP checksum */
1445                         DifferentialChecksum(&pip->ip_sum,
1446                             &original_address, &pip->ip_src, 2);
1447
1448                         /* Un-alias source address and port number */
1449                         pip->ip_src = original_address;
1450                         if (pip->ip_p == IPPROTO_UDP)
1451                                 ud->uh_sport = original_port;
1452                         else
1453                                 tc->th_sport = original_port;
1454
1455                         iresult = PKT_ALIAS_OK;
1456
1457                 } else if (pip->ip_p == IPPROTO_ICMP) {
1458
1459                         int accumulate;
1460                         struct in_addr original_address;
1461                         u_short original_id;
1462
1463                         original_address = GetOriginalAddress(lnk);
1464                         original_id = GetOriginalPort(lnk);
1465
1466                         /* Adjust ICMP checksum */
1467                         accumulate = twowords(&pip->ip_src);
1468                         accumulate -= twowords(&original_address);
1469                         accumulate += ic->icmp_id;
1470                         accumulate -= original_id;
1471                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1472
1473                         /* Adjust IP checksum */
1474                         DifferentialChecksum(&pip->ip_sum,
1475                             &original_address, &pip->ip_src, 2);
1476
1477                         /* Un-alias source address and port number */
1478                         pip->ip_src = original_address;
1479                         ic->icmp_id = original_id;
1480
1481                         iresult = PKT_ALIAS_OK;
1482                 }
1483         }
1484         return (iresult);
1485
1486 }
1487
1488 #ifndef _KERNEL
1489
1490 int
1491 LibAliasRefreshModules(void)
1492 {
1493         char buf[256], conf[] = "/etc/libalias.conf";
1494         FILE *fd;
1495         int len;
1496
1497         fd = fopen(conf, "r");
1498         if (fd == NULL)
1499                 err(1, "fopen(%s)", conf);
1500
1501         LibAliasUnLoadAllModule();
1502
1503         for (;;) {
1504                 fgets(buf, 256, fd);
1505                 if feof(fd) 
1506                         break;
1507                 len = strlen(buf);
1508                 if (len > 1) {
1509                         buf[len - 1] = '\0';
1510                         printf("Loading %s\n", buf);
1511                         LibAliasLoadModule(buf);
1512                 }
1513         }
1514         return (0);
1515 }
1516
1517 int
1518 LibAliasLoadModule(char *path)
1519 {
1520         struct dll *t;
1521         void *handle;
1522         struct proto_handler *m;
1523         const char *error;
1524         moduledata_t *p;
1525
1526         handle = dlopen (path, RTLD_LAZY);
1527         if (!handle) {
1528             fputs (dlerror(), stderr);
1529             return (EINVAL);
1530         }
1531
1532         p = dlsym(handle, "alias_mod");
1533         if ((error = dlerror()) != NULL)  {
1534             fputs(error, stderr);
1535             return (EINVAL);
1536         }
1537         
1538         t = malloc(sizeof(struct dll));
1539         if (t == NULL)
1540                 return (ENOMEM);
1541         strncpy(t->name, p->name, DLL_LEN);
1542         t->handle = handle;
1543         if (attach_dll(t) == EEXIST) {
1544                 free(t);
1545                 fputs("dll conflict", stderr);
1546                 return (EEXIST);
1547         }
1548
1549         m = dlsym(t->handle, "handlers");
1550         if ((error = dlerror()) != NULL)  {
1551             fputs(error, stderr);
1552             return (EINVAL);
1553         }       
1554
1555         LibAliasAttachHandlers(m);
1556         return (0);
1557 }
1558
1559 int
1560 LibAliasUnLoadAllModule(void)
1561 {
1562         struct dll *t;
1563         struct proto_handler *p;
1564
1565         /* Unload all modules then reload everything. */
1566         while ((p = first_handler()) != NULL) { 
1567                 detach_handler(p);
1568         }
1569         while ((t = walk_dll_chain()) != NULL) {        
1570                 dlclose(t->handle);
1571                 free(t);
1572         }
1573         return (1);
1574 }
1575
1576 #endif