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