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