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