]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias.c
MFV r337744:
[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         int iresult;
445         struct icmp *ic;
446
447         LIBALIAS_LOCK_ASSERT(la);
448 /* Return if proxy-only mode is enabled */
449         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
450                 return (PKT_ALIAS_OK);
451
452         ic = (struct icmp *)ip_next(pip);
453
454         iresult = PKT_ALIAS_IGNORED;
455         switch (ic->icmp_type) {
456         case ICMP_ECHOREPLY:
457         case ICMP_TSTAMPREPLY:
458                 if (ic->icmp_code == 0) {
459                         iresult = IcmpAliasIn1(la, pip);
460                 }
461                 break;
462         case ICMP_UNREACH:
463         case ICMP_SOURCEQUENCH:
464         case ICMP_TIMXCEED:
465         case ICMP_PARAMPROB:
466                 iresult = IcmpAliasIn2(la, pip);
467                 break;
468         case ICMP_ECHO:
469         case ICMP_TSTAMP:
470                 iresult = IcmpAliasIn1(la, pip);
471                 break;
472         }
473         return (iresult);
474 }
475
476
477 static int
478 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
479 {
480 /*
481     Alias outgoing echo and timestamp requests.
482     De-alias outgoing echo and timestamp replies.
483 */
484         struct alias_link *lnk;
485         struct icmp *ic;
486
487         LIBALIAS_LOCK_ASSERT(la);
488         ic = (struct icmp *)ip_next(pip);
489
490 /* Save overwritten data for when echo packet returns */
491         lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
492         if (lnk != NULL) {
493                 u_short alias_id;
494                 int accumulate;
495
496                 alias_id = GetAliasPort(lnk);
497
498 /* Since data field is being modified, adjust ICMP checksum */
499                 accumulate = ic->icmp_id;
500                 accumulate -= alias_id;
501                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
502
503 /* Alias sequence number */
504                 ic->icmp_id = alias_id;
505
506 /* Change source address */
507                 {
508                         struct in_addr alias_address;
509
510                         alias_address = GetAliasAddress(lnk);
511                         DifferentialChecksum(&pip->ip_sum,
512                             &alias_address, &pip->ip_src, 2);
513                         pip->ip_src = alias_address;
514                 }
515
516                 return (PKT_ALIAS_OK);
517         }
518         return (PKT_ALIAS_IGNORED);
519 }
520
521
522 static int
523 IcmpAliasOut2(struct libalias *la, struct ip *pip)
524 {
525 /*
526     Alias outgoing ICMP error messages containing
527     IP header and first 64 bits of datagram.
528 */
529         struct ip *ip;
530         struct icmp *ic, *ic2;
531         struct udphdr *ud;
532         struct tcphdr *tc;
533         struct alias_link *lnk;
534
535         LIBALIAS_LOCK_ASSERT(la);
536         ic = (struct icmp *)ip_next(pip);
537         ip = &ic->icmp_ip;
538
539         ud = (struct udphdr *)ip_next(ip);
540         tc = (struct tcphdr *)ip_next(ip);
541         ic2 = (struct icmp *)ip_next(ip);
542
543         if (ip->ip_p == IPPROTO_UDP)
544                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
545                     ud->uh_dport, ud->uh_sport,
546                     IPPROTO_UDP, 0);
547         else if (ip->ip_p == IPPROTO_TCP)
548                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
549                     tc->th_dport, tc->th_sport,
550                     IPPROTO_TCP, 0);
551         else if (ip->ip_p == IPPROTO_ICMP) {
552                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
553                         lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
554                 else
555                         lnk = NULL;
556         } else
557                 lnk = NULL;
558
559         if (lnk != NULL) {
560                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
561                         int accumulate;
562                         struct in_addr alias_address;
563                         u_short alias_port;
564
565                         alias_address = GetAliasAddress(lnk);
566                         alias_port = GetAliasPort(lnk);
567
568 /* Adjust ICMP checksum */
569                         accumulate = twowords(&ip->ip_dst);
570                         accumulate -= twowords(&alias_address);
571                         accumulate += ud->uh_dport;
572                         accumulate -= alias_port;
573                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
574
575 /*
576  * Alias address in IP header if it comes from the host
577  * the original TCP/UDP packet was destined for.
578  */
579                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
580                                 DifferentialChecksum(&pip->ip_sum,
581                                     &alias_address, &pip->ip_src, 2);
582                                 pip->ip_src = alias_address;
583                         }
584 /* Alias address and port number of original IP packet
585 fragment contained in ICMP data section */
586                         ip->ip_dst = alias_address;
587                         ud->uh_dport = alias_port;
588                 } else if (ip->ip_p == IPPROTO_ICMP) {
589                         int accumulate;
590                         struct in_addr alias_address;
591                         u_short alias_id;
592
593                         alias_address = GetAliasAddress(lnk);
594                         alias_id = GetAliasPort(lnk);
595
596 /* Adjust ICMP checksum */
597                         accumulate = twowords(&ip->ip_dst);
598                         accumulate -= twowords(&alias_address);
599                         accumulate += ic2->icmp_id;
600                         accumulate -= alias_id;
601                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
602
603 /*
604  * Alias address in IP header if it comes from the host
605  * the original ICMP message was destined for.
606  */
607                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
608                                 DifferentialChecksum(&pip->ip_sum,
609                                     &alias_address, &pip->ip_src, 2);
610                                 pip->ip_src = alias_address;
611                         }
612 /* Alias address of original IP packet and sequence number of
613    embedded ICMP datagram */
614                         ip->ip_dst = alias_address;
615                         ic2->icmp_id = alias_id;
616                 }
617                 return (PKT_ALIAS_OK);
618         }
619         return (PKT_ALIAS_IGNORED);
620 }
621
622
623 static int
624 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
625 {
626         int iresult;
627         struct icmp *ic;
628
629         LIBALIAS_LOCK_ASSERT(la);
630         (void)create;
631
632 /* Return if proxy-only mode is enabled */
633         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
634                 return (PKT_ALIAS_OK);
635
636         ic = (struct icmp *)ip_next(pip);
637
638         iresult = PKT_ALIAS_IGNORED;
639         switch (ic->icmp_type) {
640         case ICMP_ECHO:
641         case ICMP_TSTAMP:
642                 if (ic->icmp_code == 0) {
643                         iresult = IcmpAliasOut1(la, pip, create);
644                 }
645                 break;
646         case ICMP_UNREACH:
647         case ICMP_SOURCEQUENCH:
648         case ICMP_TIMXCEED:
649         case ICMP_PARAMPROB:
650                 iresult = IcmpAliasOut2(la, pip);
651                 break;
652         case ICMP_ECHOREPLY:
653         case ICMP_TSTAMPREPLY:
654                 iresult = IcmpAliasOut1(la, pip, create);
655         }
656         return (iresult);
657 }
658
659 static int
660 ProtoAliasIn(struct libalias *la, struct in_addr ip_src, 
661     struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum)
662 {
663 /*
664   Handle incoming IP packets. The
665   only thing which is done in this case is to alias
666   the dest IP address of the packet to our inside
667   machine.
668 */
669         struct alias_link *lnk;
670
671         LIBALIAS_LOCK_ASSERT(la);
672 /* Return if proxy-only mode is enabled */
673         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
674                 return (PKT_ALIAS_OK);
675
676         lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p);
677         if (lnk != NULL) {
678                 struct in_addr original_address;
679
680                 original_address = GetOriginalAddress(lnk);
681
682 /* Restore original IP address */
683                 DifferentialChecksum(ip_sum,
684                     &original_address, ip_dst, 2);
685                 *ip_dst = original_address;
686
687                 return (PKT_ALIAS_OK);
688         }
689         return (PKT_ALIAS_IGNORED);
690 }
691
692 static int
693 ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 
694     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
695 {
696 /*
697   Handle outgoing IP packets. The
698   only thing which is done in this case is to alias
699   the source IP address of the packet.
700 */
701         struct alias_link *lnk;
702
703         LIBALIAS_LOCK_ASSERT(la);
704
705 /* Return if proxy-only mode is enabled */
706         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
707                 return (PKT_ALIAS_OK);
708
709         if (!create)
710                 return (PKT_ALIAS_IGNORED);
711
712         lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
713         if (lnk != NULL) {
714                 struct in_addr alias_address;
715
716                 alias_address = GetAliasAddress(lnk);
717
718 /* Change source address */
719                 DifferentialChecksum(ip_sum,
720                     &alias_address, ip_src, 2);
721                 *ip_src = alias_address;
722
723                 return (PKT_ALIAS_OK);
724         }
725         return (PKT_ALIAS_IGNORED);
726 }
727
728
729 static int
730 UdpAliasIn(struct libalias *la, struct ip *pip)
731 {
732         struct udphdr *ud;
733         struct alias_link *lnk;
734
735         LIBALIAS_LOCK_ASSERT(la);
736
737         ud = (struct udphdr *)ip_next(pip);
738
739         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
740             ud->uh_sport, ud->uh_dport,
741             IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
742         if (lnk != NULL) {
743                 struct in_addr alias_address;
744                 struct in_addr original_address;
745                 struct in_addr proxy_address;
746                 u_short alias_port;
747                 u_short proxy_port;
748                 int accumulate;
749                 int error;
750                 struct alias_data ad = {
751                         .lnk = lnk, 
752                         .oaddr = &original_address, 
753                         .aaddr = &alias_address,
754                         .aport = &alias_port,
755                         .sport = &ud->uh_sport,
756                         .dport = &ud->uh_dport,
757                         .maxpktsize = 0
758                 };
759
760                 alias_address = GetAliasAddress(lnk);
761                 original_address = GetOriginalAddress(lnk);
762                 proxy_address = GetProxyAddress(lnk);
763                 alias_port = ud->uh_dport;
764                 ud->uh_dport = GetOriginalPort(lnk);
765                 proxy_port = GetProxyPort(lnk);
766
767                 /* Walk out chain. */           
768                 error = find_handler(IN, UDP, la, pip, &ad);
769                 /* If we cannot figure out the packet, ignore it. */
770                 if (error < 0)
771                         return (PKT_ALIAS_IGNORED);
772
773 /* If UDP checksum is not zero, then adjust since destination port */
774 /* is being unaliased and destination address is being altered.    */
775                 if (ud->uh_sum != 0) {
776                         accumulate = alias_port;
777                         accumulate -= ud->uh_dport;
778                         accumulate += twowords(&alias_address);
779                         accumulate -= twowords(&original_address);
780
781 /* If this is a proxy packet, modify checksum because of source change.*/
782                         if (proxy_port != 0) {
783                                 accumulate += ud->uh_sport;
784                                 accumulate -= proxy_port;
785                         }
786
787                         if (proxy_address.s_addr != 0) {
788                                 accumulate += twowords(&pip->ip_src);
789                                 accumulate -= twowords(&proxy_address);
790                         }
791
792                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
793                 }
794 /* XXX: Could the two if's below be concatenated to one ? */
795 /* Restore source port and/or address in case of proxying*/
796
797                 if (proxy_port != 0)
798                         ud->uh_sport = proxy_port;
799
800                 if (proxy_address.s_addr != 0) {
801                         DifferentialChecksum(&pip->ip_sum,
802                             &proxy_address, &pip->ip_src, 2);
803                         pip->ip_src = proxy_address;
804                 }
805
806 /* Restore original IP address */
807                 DifferentialChecksum(&pip->ip_sum,
808                     &original_address, &pip->ip_dst, 2);
809                 pip->ip_dst = original_address;
810
811                 return (PKT_ALIAS_OK);
812         }
813         return (PKT_ALIAS_IGNORED);
814 }
815
816 static int
817 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
818 {
819         struct udphdr *ud;
820         struct alias_link *lnk;
821         struct in_addr dest_address;
822         struct in_addr proxy_server_address;
823         u_short dest_port;
824         u_short proxy_server_port;
825         int proxy_type;
826         int error;
827
828         LIBALIAS_LOCK_ASSERT(la);
829
830 /* Return if proxy-only mode is enabled and not proxyrule found.*/
831         ud = (struct udphdr *)ip_next(pip);
832         proxy_type = ProxyCheck(la, &proxy_server_address, 
833                 &proxy_server_port, pip->ip_src, pip->ip_dst, 
834                 ud->uh_dport, pip->ip_p);
835         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
836                 return (PKT_ALIAS_OK);
837
838 /* If this is a transparent proxy, save original destination,
839  * then alter the destination and adjust checksums */
840         dest_port = ud->uh_dport;
841         dest_address = pip->ip_dst;
842
843         if (proxy_type != 0) {
844                 int accumulate;
845
846                 accumulate = twowords(&pip->ip_dst);
847                 accumulate -= twowords(&proxy_server_address);
848
849                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
850
851                 if (ud->uh_sum != 0) {
852                         accumulate = twowords(&pip->ip_dst);
853                         accumulate -= twowords(&proxy_server_address);
854                         accumulate += ud->uh_dport;
855                         accumulate -= proxy_server_port;
856                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
857                 }
858                 pip->ip_dst = proxy_server_address;
859                 ud->uh_dport = proxy_server_port;
860         }
861         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
862             ud->uh_sport, ud->uh_dport,
863             IPPROTO_UDP, create);
864         if (lnk != NULL) {
865                 u_short alias_port;
866                 struct in_addr alias_address;
867                 struct alias_data ad = {
868                         .lnk = lnk, 
869                         .oaddr = NULL,
870                         .aaddr = &alias_address,
871                         .aport = &alias_port,
872                         .sport = &ud->uh_sport,
873                         .dport = &ud->uh_dport,
874                         .maxpktsize = 0
875                 };
876
877 /* Save original destination address, if this is a proxy packet.
878  * Also modify packet to include destination encoding.  This may
879  * change the size of IP header. */
880                 if (proxy_type != 0) {
881                         SetProxyPort(lnk, dest_port);
882                         SetProxyAddress(lnk, dest_address);
883                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
884                         ud = (struct udphdr *)ip_next(pip);
885                 }
886
887                 alias_address = GetAliasAddress(lnk);
888                 alias_port = GetAliasPort(lnk);
889
890                 /* Walk out chain. */           
891                 error = find_handler(OUT, UDP, la, pip, &ad);
892
893 /* If UDP checksum is not zero, adjust since source port is */
894 /* being aliased and source address is being altered        */
895                 if (ud->uh_sum != 0) {
896                         int accumulate;
897
898                         accumulate = ud->uh_sport;
899                         accumulate -= alias_port;
900                         accumulate += twowords(&pip->ip_src);
901                         accumulate -= twowords(&alias_address);
902                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
903                 }
904 /* Put alias port in UDP header */
905                 ud->uh_sport = alias_port;
906
907 /* Change source address */
908                 DifferentialChecksum(&pip->ip_sum,
909                     &alias_address, &pip->ip_src, 2);
910                 pip->ip_src = alias_address;
911
912                 return (PKT_ALIAS_OK);
913         }
914         return (PKT_ALIAS_IGNORED);
915 }
916
917
918
919 static int
920 TcpAliasIn(struct libalias *la, struct ip *pip)
921 {
922         struct tcphdr *tc;
923         struct alias_link *lnk;
924
925         LIBALIAS_LOCK_ASSERT(la);
926         tc = (struct tcphdr *)ip_next(pip);
927
928         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
929             tc->th_sport, tc->th_dport,
930             IPPROTO_TCP,
931             !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
932         if (lnk != NULL) {
933                 struct in_addr alias_address;
934                 struct in_addr original_address;
935                 struct in_addr proxy_address;
936                 u_short alias_port;
937                 u_short proxy_port;
938                 int accumulate, error;
939
940                 /* 
941                  * The init of MANY vars is a bit below, but aliashandlepptpin 
942                  * seems to need the destination port that came within the
943                  * packet and not the original one looks below [*].
944                  */
945
946                 struct alias_data ad = {
947                         .lnk = lnk, 
948                         .oaddr = NULL,
949                         .aaddr = NULL,
950                         .aport = NULL,
951                         .sport = &tc->th_sport,
952                         .dport = &tc->th_dport,
953                         .maxpktsize = 0
954                 };
955
956                 /* Walk out chain. */           
957                 error = find_handler(IN, TCP, la, pip, &ad);
958
959                 alias_address = GetAliasAddress(lnk);
960                 original_address = GetOriginalAddress(lnk);
961                 proxy_address = GetProxyAddress(lnk);
962                 alias_port = tc->th_dport;
963                 tc->th_dport = GetOriginalPort(lnk);
964                 proxy_port = GetProxyPort(lnk);
965
966                 /* 
967                  * Look above, if anyone is going to add find_handler AFTER 
968                  * this aliashandlepptpin/point, please redo alias_data too.
969                  * Uncommenting the piece here below should be enough.
970                  */
971 #if 0
972                                  struct alias_data ad = {
973                                         .lnk = lnk,
974                                         .oaddr = &original_address,
975                                         .aaddr = &alias_address,
976                                         .aport = &alias_port,
977                                         .sport = &ud->uh_sport,
978                                         .dport = &ud->uh_dport,
979                                         .maxpktsize = 0
980                                 };
981                 
982                                 /* Walk out chain. */
983                                 error = find_handler(la, pip, &ad);
984                                 if (error == EHDNOF)
985                                         printf("Protocol handler not found\n");
986 #endif
987
988 /* Adjust TCP checksum since destination port is being unaliased */
989 /* and destination port is being altered.                        */
990                 accumulate = alias_port;
991                 accumulate -= tc->th_dport;
992                 accumulate += twowords(&alias_address);
993                 accumulate -= twowords(&original_address);
994
995 /* If this is a proxy, then modify the TCP source port and
996    checksum accumulation */
997                 if (proxy_port != 0) {
998                         accumulate += tc->th_sport;
999                         tc->th_sport = proxy_port;
1000                         accumulate -= tc->th_sport;
1001                         accumulate += twowords(&pip->ip_src);
1002                         accumulate -= twowords(&proxy_address);
1003                 }
1004 /* See if ACK number needs to be modified */
1005                 if (GetAckModified(lnk) == 1) {
1006                         int delta;
1007
1008                         tc = (struct tcphdr *)ip_next(pip);
1009                         delta = GetDeltaAckIn(tc->th_ack, lnk);
1010                         if (delta != 0) {
1011                                 accumulate += twowords(&tc->th_ack);
1012                                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1013                                 accumulate -= twowords(&tc->th_ack);
1014                         }
1015                 }
1016                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1017
1018 /* Restore original IP address */
1019                 accumulate = twowords(&pip->ip_dst);
1020                 pip->ip_dst = original_address;
1021                 accumulate -= twowords(&pip->ip_dst);
1022
1023 /* If this is a transparent proxy packet, then modify the source
1024    address */
1025                 if (proxy_address.s_addr != 0) {
1026                         accumulate += twowords(&pip->ip_src);
1027                         pip->ip_src = proxy_address;
1028                         accumulate -= twowords(&pip->ip_src);
1029                 }
1030                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1031
1032 /* Monitor TCP connection state */
1033                 tc = (struct tcphdr *)ip_next(pip);
1034                 TcpMonitorIn(tc->th_flags, lnk);
1035
1036                 return (PKT_ALIAS_OK);
1037         }
1038         return (PKT_ALIAS_IGNORED);
1039 }
1040
1041 static int
1042 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1043 {
1044         int proxy_type, error;
1045         u_short dest_port;
1046         u_short proxy_server_port;
1047         struct in_addr dest_address;
1048         struct in_addr proxy_server_address;
1049         struct tcphdr *tc;
1050         struct alias_link *lnk;
1051
1052         LIBALIAS_LOCK_ASSERT(la);
1053         tc = (struct tcphdr *)ip_next(pip);
1054
1055         if (create)
1056                 proxy_type = ProxyCheck(la, &proxy_server_address, 
1057                     &proxy_server_port, pip->ip_src, pip->ip_dst, 
1058                     tc->th_dport, pip->ip_p);
1059         else
1060                 proxy_type = 0;
1061
1062         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1063                 return (PKT_ALIAS_OK);
1064
1065 /* If this is a transparent proxy, save original destination,
1066    then alter the destination and adjust checksums */
1067         dest_port = tc->th_dport;
1068         dest_address = pip->ip_dst;
1069         if (proxy_type != 0) {
1070                 int accumulate;
1071
1072                 accumulate = tc->th_dport;
1073                 tc->th_dport = proxy_server_port;
1074                 accumulate -= tc->th_dport;
1075                 accumulate += twowords(&pip->ip_dst);
1076                 accumulate -= twowords(&proxy_server_address);
1077                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1078
1079                 accumulate = twowords(&pip->ip_dst);
1080                 pip->ip_dst = proxy_server_address;
1081                 accumulate -= twowords(&pip->ip_dst);
1082                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1083         }
1084         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1085             tc->th_sport, tc->th_dport,
1086             IPPROTO_TCP, create);
1087         if (lnk == NULL)
1088                 return (PKT_ALIAS_IGNORED);
1089         if (lnk != NULL) {
1090                 u_short alias_port;
1091                 struct in_addr alias_address;
1092                 int accumulate;
1093                 struct alias_data ad = {
1094                         .lnk = lnk, 
1095                         .oaddr = NULL,
1096                         .aaddr = &alias_address,
1097                         .aport = &alias_port,
1098                         .sport = &tc->th_sport,
1099                         .dport = &tc->th_dport,
1100                         .maxpktsize = maxpacketsize
1101                 };
1102
1103 /* Save original destination address, if this is a proxy packet.
1104    Also modify packet to include destination encoding.  This may
1105    change the size of IP header. */
1106                 if (proxy_type != 0) {
1107                         SetProxyPort(lnk, dest_port);
1108                         SetProxyAddress(lnk, dest_address);
1109                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1110                         tc = (struct tcphdr *)ip_next(pip);
1111                 }
1112 /* Get alias address and port */
1113                 alias_port = GetAliasPort(lnk);
1114                 alias_address = GetAliasAddress(lnk);
1115
1116 /* Monitor TCP connection state */
1117                 tc = (struct tcphdr *)ip_next(pip);
1118                 TcpMonitorOut(tc->th_flags, lnk);
1119                 
1120                 /* Walk out chain. */           
1121                 error = find_handler(OUT, TCP, la, pip, &ad);
1122
1123 /* Adjust TCP checksum since source port is being aliased */
1124 /* and source address is being altered                    */
1125                 accumulate = tc->th_sport;
1126                 tc->th_sport = alias_port;
1127                 accumulate -= tc->th_sport;
1128                 accumulate += twowords(&pip->ip_src);
1129                 accumulate -= twowords(&alias_address);
1130
1131 /* Modify sequence number if necessary */
1132                 if (GetAckModified(lnk) == 1) {
1133                         int delta;
1134                         
1135                         tc = (struct tcphdr *)ip_next(pip);
1136                         delta = GetDeltaSeqOut(tc->th_seq, lnk);
1137                         if (delta != 0) {
1138                                 accumulate += twowords(&tc->th_seq);
1139                                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1140                                 accumulate -= twowords(&tc->th_seq);
1141                         }
1142                 }
1143                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1144
1145 /* Change source address */
1146                 accumulate = twowords(&pip->ip_src);
1147                 pip->ip_src = alias_address;
1148                 accumulate -= twowords(&pip->ip_src);
1149                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1150
1151                 return (PKT_ALIAS_OK);
1152         }
1153         return (PKT_ALIAS_IGNORED);
1154 }
1155
1156
1157
1158
1159 /* Fragment Handling
1160
1161     FragmentIn()
1162     FragmentOut()
1163
1164 The packet aliasing module has a limited ability for handling IP
1165 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1166 received, then the ID number of the IP packet is saved, and other
1167 fragments are identified according to their ID number and IP address
1168 they were sent from.  Pointers to unresolved fragments can also be
1169 saved and recalled when a header fragment is seen.
1170 */
1171
1172 /* Local prototypes */
1173 static int      FragmentIn(struct libalias *la, struct in_addr ip_src, 
1174                     struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);                
1175 static int      FragmentOut(struct libalias *, struct in_addr *ip_src, 
1176                     u_short *ip_sum);
1177
1178 static int
1179 FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1180     u_short ip_id, u_short *ip_sum)
1181 {
1182         struct alias_link *lnk;
1183
1184         LIBALIAS_LOCK_ASSERT(la);
1185         lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1186         if (lnk != NULL) {
1187                 struct in_addr original_address;
1188
1189                 GetFragmentAddr(lnk, &original_address);
1190                 DifferentialChecksum(ip_sum,
1191                     &original_address, ip_dst, 2);
1192                 *ip_dst = original_address;
1193
1194                 return (PKT_ALIAS_OK);
1195         }
1196         return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1197 }
1198
1199 static int
1200 FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
1201 {
1202         struct in_addr alias_address;
1203
1204         LIBALIAS_LOCK_ASSERT(la);
1205         alias_address = FindAliasAddress(la, *ip_src);
1206         DifferentialChecksum(ip_sum,
1207             &alias_address, ip_src, 2);
1208         *ip_src = alias_address;
1209
1210         return (PKT_ALIAS_OK);
1211 }
1212
1213
1214
1215
1216
1217
1218 /* Outside World Access
1219
1220         PacketAliasSaveFragment()
1221         PacketAliasGetFragment()
1222         PacketAliasFragmentIn()
1223         PacketAliasIn()
1224         PacketAliasOut()
1225         PacketUnaliasOut()
1226
1227 (prototypes in alias.h)
1228 */
1229
1230 int
1231 LibAliasSaveFragment(struct libalias *la, char *ptr)
1232 {
1233         int iresult;
1234         struct alias_link *lnk;
1235         struct ip *pip;
1236
1237         LIBALIAS_LOCK(la);
1238         pip = (struct ip *)ptr;
1239         lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1240         iresult = PKT_ALIAS_ERROR;
1241         if (lnk != NULL) {
1242                 SetFragmentPtr(lnk, ptr);
1243                 iresult = PKT_ALIAS_OK;
1244         }
1245         LIBALIAS_UNLOCK(la);
1246         return (iresult);
1247 }
1248
1249 char           *
1250 LibAliasGetFragment(struct libalias *la, char *ptr)
1251 {
1252         struct alias_link *lnk;
1253         char *fptr;
1254         struct ip *pip;
1255
1256         LIBALIAS_LOCK(la);
1257         pip = (struct ip *)ptr;
1258         lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1259         if (lnk != NULL) {
1260                 GetFragmentPtr(lnk, &fptr);
1261                 SetFragmentPtr(lnk, NULL);
1262                 SetExpire(lnk, 0);      /* Deletes link */
1263         } else          
1264                 fptr = NULL;
1265
1266         LIBALIAS_UNLOCK(la);
1267         return (fptr);
1268 }
1269
1270 void
1271 LibAliasFragmentIn(struct libalias *la, char *ptr,      /* Points to correctly
1272                                                          * de-aliased header
1273                                                          * fragment */
1274     char *ptr_fragment          /* Points to fragment which must be
1275                                  * de-aliased   */
1276 )
1277 {
1278         struct ip *pip;
1279         struct ip *fpip;
1280
1281         LIBALIAS_LOCK(la);
1282         (void)la;
1283         pip = (struct ip *)ptr;
1284         fpip = (struct ip *)ptr_fragment;
1285
1286         DifferentialChecksum(&fpip->ip_sum,
1287             &pip->ip_dst, &fpip->ip_dst, 2);
1288         fpip->ip_dst = pip->ip_dst;
1289         LIBALIAS_UNLOCK(la);
1290 }
1291
1292 /* Local prototypes */
1293 static int
1294 LibAliasOutLocked(struct libalias *la, char *ptr,
1295                   int maxpacketsize, int create);
1296 static int
1297 LibAliasInLocked(struct libalias *la, char *ptr,
1298                   int maxpacketsize);
1299
1300 int
1301 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1302 {
1303         int res;
1304
1305         LIBALIAS_LOCK(la);
1306         res = LibAliasInLocked(la, ptr, maxpacketsize);
1307         LIBALIAS_UNLOCK(la);
1308         return (res);
1309 }
1310
1311 static int
1312 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1313 {
1314         struct in_addr alias_addr;
1315         struct ip *pip;
1316         int iresult;
1317
1318         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1319                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1320                 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1321                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1322                 goto getout;
1323         }
1324         HouseKeeping(la);
1325         ClearCheckNewLink(la);
1326         pip = (struct ip *)ptr;
1327         alias_addr = pip->ip_dst;
1328
1329         /* Defense against mangled packets */
1330         if (ntohs(pip->ip_len) > maxpacketsize
1331             || (pip->ip_hl << 2) > maxpacketsize) {
1332                 iresult = PKT_ALIAS_IGNORED; 
1333                 goto getout;
1334         }
1335
1336         iresult = PKT_ALIAS_IGNORED;
1337         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1338                 switch (pip->ip_p) {
1339                 case IPPROTO_ICMP:
1340                         iresult = IcmpAliasIn(la, pip);
1341                         break;
1342                 case IPPROTO_UDP:
1343                         iresult = UdpAliasIn(la, pip);
1344                         break;
1345                 case IPPROTO_TCP:
1346                         iresult = TcpAliasIn(la, pip);
1347                         break;
1348 #ifdef _KERNEL
1349                 case IPPROTO_SCTP:
1350                   iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1351                         break;
1352 #endif
1353                 case IPPROTO_GRE: {
1354                         int error;
1355                         struct alias_data ad = {
1356                                 .lnk = NULL, 
1357                                 .oaddr = NULL, 
1358                                 .aaddr = NULL,
1359                                 .aport = NULL,
1360                                 .sport = NULL,
1361                                 .dport = NULL,
1362                                 .maxpktsize = 0                  
1363                         };
1364                         
1365                         /* Walk out chain. */           
1366                         error = find_handler(IN, IP, la, pip, &ad);
1367                         if (error ==  0)
1368                                 iresult = PKT_ALIAS_OK;
1369                         else
1370                                 iresult = ProtoAliasIn(la, pip->ip_src, 
1371                                     &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1372                 }
1373                         break; 
1374                 default:
1375                         iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1376                             pip->ip_p, &pip->ip_sum);
1377                         break;
1378                 }
1379
1380                 if (ntohs(pip->ip_off) & IP_MF) {
1381                         struct alias_link *lnk;
1382
1383                         lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1384                         if (lnk != NULL) {
1385                                 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1386                                 SetFragmentAddr(lnk, pip->ip_dst);
1387                         } else {
1388                                 iresult = PKT_ALIAS_ERROR;
1389                         }
1390                 }
1391         } else {
1392                 iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1393                     &pip->ip_sum);
1394         }
1395
1396 getout:
1397         return (iresult);
1398 }
1399
1400
1401
1402 /* Unregistered address ranges */
1403
1404 /* 10.0.0.0   ->   10.255.255.255 */
1405 #define UNREG_ADDR_A_LOWER 0x0a000000
1406 #define UNREG_ADDR_A_UPPER 0x0affffff
1407
1408 /* 172.16.0.0  ->  172.31.255.255 */
1409 #define UNREG_ADDR_B_LOWER 0xac100000
1410 #define UNREG_ADDR_B_UPPER 0xac1fffff
1411
1412 /* 192.168.0.0 -> 192.168.255.255 */
1413 #define UNREG_ADDR_C_LOWER 0xc0a80000
1414 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1415
1416 int
1417 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1418 {
1419         int res;
1420
1421         LIBALIAS_LOCK(la);
1422         res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1423         LIBALIAS_UNLOCK(la);
1424         return (res);
1425 }
1426
1427 int
1428 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1429 {
1430         int res;
1431
1432         LIBALIAS_LOCK(la);
1433         res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1434         LIBALIAS_UNLOCK(la);
1435         return (res);
1436 }
1437
1438 static int
1439 LibAliasOutLocked(struct libalias *la, char *ptr,       /* valid IP packet */
1440     int maxpacketsize,          /* How much the packet data may grow (FTP
1441                                  * and IRC inline changes) */
1442     int create                  /* Create new entries ? */
1443 )
1444 {
1445         int iresult;
1446         struct in_addr addr_save;
1447         struct ip *pip;
1448
1449         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1450                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1451                 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1452                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1453                 goto getout;
1454         }
1455         HouseKeeping(la);
1456         ClearCheckNewLink(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                 iresult = PKT_ALIAS_IGNORED;
1463                 goto getout;
1464         }
1465
1466         addr_save = GetDefaultAliasAddress(la);
1467         if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1468                 u_long addr;
1469                 int iclass;
1470
1471                 iclass = 0;
1472                 addr = ntohl(pip->ip_src.s_addr);
1473                 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1474                         iclass = 3;
1475                 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1476                         iclass = 2;
1477                 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1478                         iclass = 1;
1479
1480                 if (iclass == 0) {
1481                         SetDefaultAliasAddress(la, pip->ip_src);
1482                 }
1483         } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1484                 SetDefaultAliasAddress(la, pip->ip_src);
1485         }
1486         iresult = PKT_ALIAS_IGNORED;
1487         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1488                 switch (pip->ip_p) {
1489                 case IPPROTO_ICMP:
1490                         iresult = IcmpAliasOut(la, pip, create);
1491                         break;
1492                 case IPPROTO_UDP:
1493                         iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1494                         break;
1495                 case IPPROTO_TCP:
1496                         iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1497                         break;
1498 #ifdef _KERNEL
1499                 case IPPROTO_SCTP:
1500                   iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1501                         break;
1502 #endif
1503                 case IPPROTO_GRE: {
1504                         int error;
1505                         struct alias_data ad = {
1506                                 .lnk = NULL, 
1507                                 .oaddr = NULL, 
1508                                 .aaddr = NULL,
1509                                 .aport = NULL,
1510                                 .sport = NULL,
1511                                 .dport = NULL,
1512                                 .maxpktsize = 0                  
1513                         };
1514                         /* Walk out chain. */           
1515                         error = find_handler(OUT, IP, la, pip, &ad);
1516                         if (error == 0)
1517                                 iresult = PKT_ALIAS_OK;
1518                         else
1519                                 iresult = ProtoAliasOut(la, &pip->ip_src, 
1520                                     pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1521                 }
1522                         break;
1523                 default:
1524                         iresult = ProtoAliasOut(la, &pip->ip_src,
1525                             pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1526                         break;
1527                 }
1528         } else {
1529                 iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1530         }
1531
1532         SetDefaultAliasAddress(la, addr_save);
1533 getout:
1534         return (iresult);
1535 }
1536
1537 int
1538 LibAliasUnaliasOut(struct libalias *la, char *ptr,      /* valid IP packet */
1539     int maxpacketsize           /* for error checking */
1540 )
1541 {
1542         struct ip *pip;
1543         struct icmp *ic;
1544         struct udphdr *ud;
1545         struct tcphdr *tc;
1546         struct alias_link *lnk;
1547         int iresult = PKT_ALIAS_IGNORED;
1548
1549         LIBALIAS_LOCK(la);
1550         pip = (struct ip *)ptr;
1551
1552         /* Defense against mangled packets */
1553         if (ntohs(pip->ip_len) > maxpacketsize
1554             || (pip->ip_hl << 2) > maxpacketsize)
1555                 goto getout;
1556
1557         ud = (struct udphdr *)ip_next(pip);
1558         tc = (struct tcphdr *)ip_next(pip);
1559         ic = (struct icmp *)ip_next(pip);
1560
1561         /* Find a link */
1562         if (pip->ip_p == IPPROTO_UDP)
1563                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1564                     ud->uh_dport, ud->uh_sport,
1565                     IPPROTO_UDP, 0);
1566         else if (pip->ip_p == IPPROTO_TCP)
1567                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1568                     tc->th_dport, tc->th_sport,
1569                     IPPROTO_TCP, 0);
1570         else if (pip->ip_p == IPPROTO_ICMP)
1571                 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1572         else
1573                 lnk = NULL;
1574
1575         /* Change it from an aliased packet to an unaliased packet */
1576         if (lnk != NULL) {
1577                 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1578                         int accumulate;
1579                         struct in_addr original_address;
1580                         u_short original_port;
1581
1582                         original_address = GetOriginalAddress(lnk);
1583                         original_port = GetOriginalPort(lnk);
1584
1585                         /* Adjust TCP/UDP checksum */
1586                         accumulate = twowords(&pip->ip_src);
1587                         accumulate -= twowords(&original_address);
1588
1589                         if (pip->ip_p == IPPROTO_UDP) {
1590                                 accumulate += ud->uh_sport;
1591                                 accumulate -= original_port;
1592                                 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1593                         } else {
1594                                 accumulate += tc->th_sport;
1595                                 accumulate -= original_port;
1596                                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1597                         }
1598
1599                         /* Adjust IP checksum */
1600                         DifferentialChecksum(&pip->ip_sum,
1601                             &original_address, &pip->ip_src, 2);
1602
1603                         /* Un-alias source address and port number */
1604                         pip->ip_src = original_address;
1605                         if (pip->ip_p == IPPROTO_UDP)
1606                                 ud->uh_sport = original_port;
1607                         else
1608                                 tc->th_sport = original_port;
1609
1610                         iresult = PKT_ALIAS_OK;
1611
1612                 } else if (pip->ip_p == IPPROTO_ICMP) {
1613
1614                         int accumulate;
1615                         struct in_addr original_address;
1616                         u_short original_id;
1617
1618                         original_address = GetOriginalAddress(lnk);
1619                         original_id = GetOriginalPort(lnk);
1620
1621                         /* Adjust ICMP checksum */
1622                         accumulate = twowords(&pip->ip_src);
1623                         accumulate -= twowords(&original_address);
1624                         accumulate += ic->icmp_id;
1625                         accumulate -= original_id;
1626                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1627
1628                         /* Adjust IP checksum */
1629                         DifferentialChecksum(&pip->ip_sum,
1630                             &original_address, &pip->ip_src, 2);
1631
1632                         /* Un-alias source address and port number */
1633                         pip->ip_src = original_address;
1634                         ic->icmp_id = original_id;
1635
1636                         iresult = PKT_ALIAS_OK;
1637                 }
1638         }
1639 getout:
1640         LIBALIAS_UNLOCK(la);
1641         return (iresult);
1642
1643 }
1644
1645 #ifndef _KERNEL
1646
1647 int
1648 LibAliasRefreshModules(void)
1649 {
1650         char buf[256], conf[] = "/etc/libalias.conf";
1651         FILE *fd;
1652         int i, len;
1653
1654         fd = fopen(conf, "r");
1655         if (fd == NULL)
1656                 err(1, "fopen(%s)", conf);
1657
1658         LibAliasUnLoadAllModule();
1659
1660         for (;;) {
1661                 fgets(buf, 256, fd);
1662                 if (feof(fd)) 
1663                         break;
1664                 len = strlen(buf);
1665                 if (len > 1) {
1666                         for (i = 0; i < len; i++)
1667                                 if (!isspace(buf[i]))
1668                                         break;
1669                         if (buf[i] == '#')
1670                                 continue;
1671                         buf[len - 1] = '\0';
1672                         LibAliasLoadModule(buf);
1673                 }
1674         }
1675         fclose(fd);
1676         return (0);
1677 }
1678
1679 int
1680 LibAliasLoadModule(char *path)
1681 {
1682         struct dll *t;
1683         void *handle;
1684         struct proto_handler *m;
1685         const char *error;
1686         moduledata_t *p;
1687
1688         handle = dlopen (path, RTLD_LAZY);
1689         if (!handle) {
1690                 fprintf(stderr, "%s\n", dlerror());
1691                 return (EINVAL);
1692         }
1693
1694         p = dlsym(handle, "alias_mod");
1695         if ((error = dlerror()) != NULL)  {
1696                 fprintf(stderr, "%s\n", dlerror());
1697                 return (EINVAL);
1698         }
1699
1700         t = malloc(sizeof(struct dll));
1701         if (t == NULL)
1702                 return (ENOMEM);
1703         strncpy(t->name, p->name, DLL_LEN);
1704         t->handle = handle;
1705         if (attach_dll(t) == EEXIST) {
1706                 free(t);
1707                 fprintf(stderr, "dll conflict\n");
1708                 return (EEXIST);
1709         }
1710
1711         m = dlsym(t->handle, "handlers");
1712         if ((error = dlerror()) != NULL)  {
1713                 fprintf(stderr, "%s\n", error);
1714                 return (EINVAL);
1715         }
1716
1717         LibAliasAttachHandlers(m);
1718         return (0);
1719 }
1720
1721 int
1722 LibAliasUnLoadAllModule(void)
1723 {
1724         struct dll *t;
1725         struct proto_handler *p;
1726
1727         /* Unload all modules then reload everything. */
1728         while ((p = first_handler()) != NULL) { 
1729                 LibAliasDetachHandlers(p);
1730         }
1731         while ((t = walk_dll_chain()) != NULL) {        
1732                 dlclose(t->handle);
1733                 free(t);
1734         }
1735         return (1);
1736 }
1737
1738 #endif
1739
1740 #ifdef _KERNEL
1741 /*
1742  * m_megapullup() - this function is a big hack.
1743  * Thankfully, it's only used in ng_nat and ipfw+nat.
1744  *
1745  * It allocates an mbuf with cluster and copies the specified part of the chain
1746  * into cluster, so that it is all contiguous and can be accessed via a plain
1747  * (char *) pointer. This is required, because libalias doesn't know how to
1748  * handle mbuf chains.
1749  *
1750  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1751  * the input packet, on failure NULL. The input packet is always consumed.
1752  */
1753 struct mbuf *
1754 m_megapullup(struct mbuf *m, int len)
1755 {
1756         struct mbuf *mcl;
1757
1758         if (len > m->m_pkthdr.len)
1759                 goto bad;
1760
1761         if (m->m_next == NULL && M_WRITABLE(m))
1762                 return (m);
1763
1764         if (len <= MJUMPAGESIZE)
1765                 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1766         else if (len <= MJUM9BYTES)
1767                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1768         else if (len <= MJUM16BYTES)
1769                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1770         else
1771                 goto bad;
1772         if (mcl == NULL)
1773                 goto bad;
1774         m_align(mcl, len);
1775         m_move_pkthdr(mcl, m);
1776         m_copydata(m, 0, len, mtod(mcl, caddr_t));
1777         mcl->m_len = mcl->m_pkthdr.len = len;
1778         m_freem(m);
1779
1780         return (mcl);
1781 bad:
1782         m_freem(m);
1783         return (NULL);
1784 }
1785 #endif