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