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