source: rtems-libbsd/freebsd/sys/netinet/libalias/alias.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

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