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