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