]> git.saurik.com Git - apple/network_cmds.git/blame - alias/alias_db.c
network_cmds-307.0.1.tar.gz
[apple/network_cmds.git] / alias / alias_db.c
CommitLineData
7ba0088d
A
1/*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
a2c93a76
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
7ba0088d 11 *
a2c93a76
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
7ba0088d
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
a2c93a76
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
7ba0088d
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*-
23 * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 *
47 * Based upon:
48 * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.12 2001/08/21 03:50:25 brian Exp $
49 */
50
51/*
b7080c8e
A
52 Alias_db.c encapsulates all data structures used for storing
53 packet aliasing data. Other parts of the aliasing software
54 access data through functions provided in this file.
55
56 Data storage is based on the notion of a "link", which is
57 established for ICMP echo/reply packets, UDP datagrams and
58 TCP stream connections. A link stores the original source
59 and destination addresses. For UDP and TCP, it also stores
60 source and destination port numbers, as well as an alias
61 port number. Links are also used to store information about
62 fragments.
63
64 There is a facility for sweeping through and deleting old
65 links as new packets are sent through. A simple timeout is
66 used for ICMP and UDP links. TCP links are left alone unless
67 there is an incomplete connection, in which case the link
68 can be deleted after a certain amount of time.
69
70
b7080c8e
A
71 Initial version: August, 1996 (cjm)
72
73 Version 1.4: September 16, 1996 (cjm)
74 Facility for handling incoming links added.
75
76 Version 1.6: September 18, 1996 (cjm)
77 ICMP data handling simplified.
78
79 Version 1.7: January 9, 1997 (cjm)
80 Fragment handling simplified.
81 Saves pointers for unresolved fragments.
7ba0088d 82 Permits links for unspecified remote ports
b7080c8e
A
83 or unspecified remote addresses.
84 Fixed bug which did not properly zero port
85 table entries after a link was deleted.
86 Cleaned up some obsolete comments.
87
88 Version 1.8: January 14, 1997 (cjm)
89 Fixed data type error in StartPoint().
90 (This error did not exist prior to v1.7
91 and was discovered and fixed by Ari Suutari)
92
93 Version 1.9: February 1, 1997
94 Optionally, connections initiated from packet aliasing host
95 machine will will not have their port number aliased unless it
96 conflicts with an aliasing port already being used. (cjm)
97
7ba0088d
A
98 All options earlier being #ifdef'ed are now available through
99 a new interface, SetPacketAliasMode(). This allows run time
b7080c8e
A
100 control (which is now available in PPP+pktAlias through the
101 'alias' keyword). (ee)
102
103 Added ability to create an alias port without
104 either destination address or port specified.
105 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
106
107 Removed K&R style function headers
108 and general cleanup. (ee)
109
110 Added packetAliasMode to replace compiler #defines's (ee)
111
112 Allocates sockets for partially specified
113 ports if ALIAS_USE_SOCKETS defined. (cjm)
114
115 Version 2.0: March, 1997
116 SetAliasAddress() will now clean up alias links
117 if the aliasing address is changed. (cjm)
118
119 PacketAliasPermanentLink() function added to support permanent
120 links. (J. Fortes suggested the need for this.)
121 Examples:
122
123 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
124
125 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
126 unknown dest port
127
7ba0088d 128 These permanent links allow for incoming connections to
b7080c8e
A
129 machines on the local network. They can be given with a
130 user-chosen amount of specificity, with increasing specificity
131 meaning more security. (cjm)
132
133 Quite a bit of rework to the basic engine. The portTable[]
134 array, which kept track of which ports were in use was replaced
135 by a table/linked list structure. (cjm)
136
137 SetExpire() function added. (cjm)
138
139 DeleteLink() no longer frees memory association with a pointer
140 to a fragment (this bug was first recognized by E. Eklund in
141 v1.9).
142
143 Version 2.1: May, 1997 (cjm)
144 Packet aliasing engine reworked so that it can handle
145 multiple external addresses rather than just a single
146 host address.
147
148 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
149 added to the API. The first function is a more generalized
150 version of PacketAliasPermanentLink(). The second function
151 implements static network address translation.
152
7ba0088d
A
153 Version 3.2: July, 2000 (salander and satoh)
154 Added FindNewPortGroup to get contiguous range of port values.
155
156 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
157 link but not actually add one.
158
159 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
160 except that the alias port (from FindNewPortGroup) is provided
161 as input.
162
b7080c8e
A
163 See HISTORY file for additional revisions.
164*/
165
166
167/* System include files */
7ba0088d 168#include <errno.h>
b7080c8e
A
169#include <stdlib.h>
170#include <stdio.h>
171#include <unistd.h>
f47db663 172#include <syslog.h>
b7080c8e 173
7ba0088d 174#include <sys/queue.h>
b7080c8e
A
175#include <sys/socket.h>
176#include <sys/time.h>
177#include <sys/types.h>
178
179/* BSD network include files */
180#include <netinet/in_systm.h>
181#include <netinet/in.h>
182#include <netinet/ip.h>
183#include <netinet/tcp.h>
184#include <arpa/inet.h>
185
186#include "alias.h"
187#include "alias_local.h"
188
189
190
191/*
192 Constants (note: constants are also defined
193 near relevant functions or structs)
194*/
195
196/* Sizes of input and output link tables */
197#define LINK_TABLE_OUT_SIZE 101
198#define LINK_TABLE_IN_SIZE 4001
199
200/* Parameters used for cleanup of expired links */
201#define ALIAS_CLEANUP_INTERVAL_SECS 60
202#define ALIAS_CLEANUP_MAX_SPOKES 30
203
7ba0088d 204/* Timeouts (in seconds) for different link types */
b7080c8e
A
205#define ICMP_EXPIRE_TIME 60
206#define UDP_EXPIRE_TIME 60
7ba0088d 207#define PROTO_EXPIRE_TIME 60
b7080c8e
A
208#define FRAGMENT_ID_EXPIRE_TIME 10
209#define FRAGMENT_PTR_EXPIRE_TIME 30
210
211/* TCP link expire time for different cases */
212/* When the link has been used and closed - minimal grace time to
213 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
214#ifndef TCP_EXPIRE_DEAD
215# define TCP_EXPIRE_DEAD 10
216#endif
217
218/* When the link has been used and closed on one side - the other side
219 is allowed to still send data */
220#ifndef TCP_EXPIRE_SINGLEDEAD
221# define TCP_EXPIRE_SINGLEDEAD 90
222#endif
223
224/* When the link isn't yet up */
225#ifndef TCP_EXPIRE_INITIAL
226# define TCP_EXPIRE_INITIAL 300
227#endif
228
229/* When the link is up */
230#ifndef TCP_EXPIRE_CONNECTED
231# define TCP_EXPIRE_CONNECTED 86400
232#endif
233
234
ac2f15b3
A
235static int iChatAVHack = 1;
236
237
b7080c8e
A
238/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
239 These constants can be anything except zero, which indicates an
240 unknown port number. */
241
242#define NO_DEST_PORT 1
243#define NO_SRC_PORT 1
244
245
246
247/* Data Structures
248
249 The fundamental data structure used in this program is
250 "struct alias_link". Whenever a TCP connection is made,
251 a UDP datagram is sent out, or an ICMP echo request is made,
252 a link record is made (if it has not already been created).
253 The link record is identified by the source address/port
254 and the destination address/port. In the case of an ICMP
255 echo request, the source port is treated as being equivalent
7ba0088d 256 with the 16-bit ID number of the ICMP packet.
b7080c8e
A
257
258 The link record also can store some auxiliary data. For
259 TCP connections that have had sequence and acknowledgment
260 modifications, data space is available to track these changes.
7ba0088d
A
261 A state field is used to keep track in changes to the TCP
262 connection state. ID numbers of fragments can also be
b7080c8e 263 stored in the auxiliary space. Pointers to unresolved
7ba0088d 264 fragments can also be stored.
b7080c8e
A
265
266 The link records support two independent chainings. Lookup
267 tables for input and out tables hold the initial pointers
268 the link chains. On input, the lookup table indexes on alias
269 port and link type. On output, the lookup table indexes on
7ba0088d 270 source address, destination address, source port, destination
b7080c8e
A
271 port and link type.
272*/
273
7ba0088d 274struct ack_data_record /* used to save changes to ACK/sequence numbers */
b7080c8e
A
275{
276 u_long ack_old;
277 u_long ack_new;
278 int delta;
279 int active;
280};
281
7ba0088d 282struct tcp_state /* Information about TCP connection */
b7080c8e
A
283{
284 int in; /* State for outside -> inside */
285 int out; /* State for inside -> outside */
7ba0088d
A
286 int index; /* Index to ACK data array */
287 int ack_modified; /* Indicates whether ACK and sequence numbers */
b7080c8e
A
288 /* been modified */
289};
290
7ba0088d 291#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
b7080c8e
A
292 saved for a modified TCP stream */
293struct tcp_dat
294{
295 struct tcp_state state;
296 struct ack_data_record ack[N_LINK_TCP_DATA];
297 int fwhole; /* Which firewall record is used for this hole? */
298};
299
7ba0088d
A
300struct server /* LSNAT server pool (circular list) */
301{
302 struct in_addr addr;
303 u_short port;
304 struct server *next;
305};
306
b7080c8e
A
307struct alias_link /* Main data structure */
308{
309 struct in_addr src_addr; /* Address and port information */
310 struct in_addr dst_addr;
311 struct in_addr alias_addr;
312 struct in_addr proxy_addr;
313 u_short src_port;
314 u_short dst_port;
315 u_short alias_port;
316 u_short proxy_port;
7ba0088d 317 struct server *server;
b7080c8e 318
7ba0088d 319 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */
b7080c8e
A
320
321/* values for link_type */
7ba0088d
A
322#define LINK_ICMP IPPROTO_ICMP
323#define LINK_UDP IPPROTO_UDP
324#define LINK_TCP IPPROTO_TCP
325#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
326#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
327#define LINK_ADDR (IPPROTO_MAX + 3)
328#define LINK_PPTP (IPPROTO_MAX + 4)
b7080c8e
A
329
330 int flags; /* indicates special characteristics */
331
332/* flag bits */
333#define LINK_UNKNOWN_DEST_PORT 0x01
334#define LINK_UNKNOWN_DEST_ADDR 0x02
335#define LINK_PERMANENT 0x04
336#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
337#define LINK_UNFIREWALLED 0x08
7ba0088d 338#define LINK_LAST_LINE_CRLF_TERMED 0x10
ac2f15b3 339#define LINK_CONE 0x20
b7080c8e
A
340
341 int timestamp; /* Time link was last accessed */
342 int expire_time; /* Expire time for link */
343
344 int sockfd; /* socket descriptor */
345
7ba0088d
A
346 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */
347 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */
b7080c8e
A
348
349 union /* Auxiliary data */
350 {
351 char *frag_ptr;
352 struct in_addr frag_addr;
353 struct tcp_dat *tcp;
354 } data;
355};
356
357
358
359
360
361/* Global Variables
362
363 The global variables listed here are only accessed from
364 within alias_db.c and so are prefixed with the static
365 designation.
366*/
367
368int packetAliasMode; /* Mode flags */
369 /* - documented in alias.h */
370
371static struct in_addr aliasAddress; /* Address written onto source */
372 /* field of IP packet. */
373
374static struct in_addr targetAddress; /* IP address incoming packets */
375 /* are sent to if no aliasing */
376 /* link already exists */
377
378static struct in_addr nullAddress; /* Used as a dummy parameter for */
379 /* some function calls */
7ba0088d 380static LIST_HEAD(, alias_link)
b7080c8e
A
381linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
382 /* chains of link records. Each */
7ba0088d 383static LIST_HEAD(, alias_link) /* link record is doubly indexed */
b7080c8e
A
384linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
385 /* tables. */
386
387static int icmpLinkCount; /* Link statistics */
388static int udpLinkCount;
389static int tcpLinkCount;
7ba0088d
A
390static int pptpLinkCount;
391static int protoLinkCount;
b7080c8e
A
392static int fragmentIdLinkCount;
393static int fragmentPtrLinkCount;
394static int sockCount;
395
396static int cleanupIndex; /* Index to chain of link table */
397 /* being inspected for old links */
398
399static int timeStamp; /* System time in seconds for */
400 /* current packet */
401
402static int lastCleanupTime; /* Last time IncrementalCleanup() */
403 /* was called */
404
405static int houseKeepingResidual; /* used by HouseKeeping() */
406
407static int deleteAllLinks; /* If equal to zero, DeleteLink() */
408 /* will not remove permanent links */
409
410static FILE *monitorFile; /* File descriptor for link */
411 /* statistics monitoring file */
412
413static int newDefaultLink; /* Indicates if a new aliasing */
414 /* link has been created after a */
415 /* call to PacketAliasIn/Out(). */
416
417#ifndef NO_FW_PUNCH
418static int fireWallFD = -1; /* File descriptor to be able to */
419 /* control firewall. Opened by */
420 /* PacketAliasSetMode on first */
421 /* setting the PKT_ALIAS_PUNCH_FW */
422 /* flag. */
423#endif
424
b7080c8e
A
425
426
427
428
429
430
431/* Internal utility routines (used only in alias_db.c)
432
433Lookup table starting points:
434 StartPointIn() -- link table initial search point for
b7080c8e 435 incoming packets
7ba0088d
A
436 StartPointOut() -- link table initial search point for
437 outgoing packets
b7080c8e
A
438
439Miscellaneous:
440 SeqDiff() -- difference between two TCP sequences
441 ShowAliasStats() -- send alias statistics to a monitor file
442*/
443
444
445/* Local prototypes */
446static u_int StartPointIn(struct in_addr, u_short, int);
447
448static u_int StartPointOut(struct in_addr, struct in_addr,
449 u_short, u_short, int);
450
451static int SeqDiff(u_long, u_long);
452
453static void ShowAliasStats(void);
454
455#ifndef NO_FW_PUNCH
456/* Firewall control */
457static void InitPunchFW(void);
458static void UninitPunchFW(void);
459static void ClearFWHole(struct alias_link *link);
460#endif
461
462/* Log file control */
463static void InitPacketAliasLog(void);
464static void UninitPacketAliasLog(void);
465
466static u_int
467StartPointIn(struct in_addr alias_addr,
468 u_short alias_port,
469 int link_type)
470{
471 u_int n;
472
473 n = alias_addr.s_addr;
7ba0088d
A
474 if (link_type != LINK_PPTP)
475 n += alias_port;
b7080c8e
A
476 n += link_type;
477 return(n % LINK_TABLE_IN_SIZE);
478}
479
480
481static u_int
482StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
483 u_short src_port, u_short dst_port, int link_type)
484{
485 u_int n;
486
487 n = src_addr.s_addr;
488 n += dst_addr.s_addr;
7ba0088d
A
489 if (link_type != LINK_PPTP) {
490 n += src_port;
491 n += dst_port;
492 }
b7080c8e
A
493 n += link_type;
494
495 return(n % LINK_TABLE_OUT_SIZE);
496}
497
498
499static int
500SeqDiff(u_long x, u_long y)
501{
502/* Return the difference between two TCP sequence numbers */
503
504/*
505 This function is encapsulated in case there are any unusual
506 arithmetic conditions that need to be considered.
507*/
508
509 return (ntohl(y) - ntohl(x));
510}
511
512
513static void
514ShowAliasStats(void)
515{
516/* Used for debugging */
517
518 if (monitorFile)
519 {
7ba0088d 520 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
b7080c8e
A
521 icmpLinkCount,
522 udpLinkCount,
523 tcpLinkCount,
7ba0088d
A
524 pptpLinkCount,
525 protoLinkCount,
b7080c8e
A
526 fragmentIdLinkCount,
527 fragmentPtrLinkCount);
528
529 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
530 icmpLinkCount + udpLinkCount
531 + tcpLinkCount
7ba0088d
A
532 + pptpLinkCount
533 + protoLinkCount
b7080c8e
A
534 + fragmentIdLinkCount
535 + fragmentPtrLinkCount,
536 sockCount);
537
538 fflush(monitorFile);
539 }
540}
541
542
543
544
545
546/* Internal routines for finding, deleting and adding links
547
548Port Allocation:
549 GetNewPort() -- find and reserve new alias port number
550 GetSocket() -- try to allocate a socket for a given port
551
552Link creation and deletion:
553 CleanupAliasData() - remove all link chains from lookup table
554 IncrementalCleanup() - look for stale links in a single chain
555 DeleteLink() - remove link
556 AddLink() - add link
557 ReLink() - change link
558
559Link search:
560 FindLinkOut() - find link for outgoing packets
561 FindLinkIn() - find link for incoming packets
7ba0088d
A
562
563Port search:
564 FindNewPortGroup() - find an available group of ports
b7080c8e
A
565*/
566
567/* Local prototypes */
568static int GetNewPort(struct alias_link *, int);
569
570static u_short GetSocket(u_short, int *, int);
571
572static void CleanupAliasData(void);
573
574static void IncrementalCleanup(void);
575
576static void DeleteLink(struct alias_link *);
577
578static struct alias_link *
579AddLink(struct in_addr, struct in_addr, struct in_addr,
580 u_short, u_short, int, int);
581
582static struct alias_link *
583ReLink(struct alias_link *,
584 struct in_addr, struct in_addr, struct in_addr,
585 u_short, u_short, int, int);
586
587static struct alias_link *
7ba0088d 588FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int);
b7080c8e
A
589
590static struct alias_link *
591FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
592
593
594#define ALIAS_PORT_BASE 0x08000
595#define ALIAS_PORT_MASK 0x07fff
7ba0088d 596#define ALIAS_PORT_MASK_EVEN 0x07ffe
b7080c8e
A
597#define GET_NEW_PORT_MAX_ATTEMPTS 20
598
599#define GET_ALIAS_PORT -1
f47db663 600#define GET_ALIAS_EPHEMERAL_PORT -2
b7080c8e
A
601#define GET_ALIAS_ID GET_ALIAS_PORT
602
7ba0088d
A
603#define FIND_EVEN_ALIAS_BASE 1
604
b7080c8e
A
605/* GetNewPort() allocates port numbers. Note that if a port number
606 is already in use, that does not mean that it cannot be used by
607 another link concurrently. This is because GetNewPort() looks for
608 unused triplets: (dest addr, dest port, alias port). */
609
f47db663
A
610static int
611GetEphemeralPort(struct alias_link *link)
612{
613 int i;
614
615 /* Port number search */
616 for (i=0; i < GET_NEW_PORT_MAX_ATTEMPTS; i++)
617 {
618 struct sockaddr_in sock_addr;
619 socklen_t salen;
620 u_short port_net;
621 struct alias_link *search_result;
622
623 if (GetSocket(0, &link->sockfd, link->link_type) == 0)
624 return -1;
625 salen = sizeof(struct sockaddr_in);
626 if (getsockname(link->sockfd, (struct sockaddr *)&sock_addr, &salen) == -1)
627 return -1;
628 port_net = sock_addr.sin_port;
629
630 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
631 link->dst_port, port_net,
632 link->link_type, 0);
633
634 if (search_result == NULL) {
635 link->alias_port = port_net;
636 return(0);
637 }
638 close(link->sockfd);
639 link->sockfd = -1;
640 }
641 #ifdef DEBUG
642 fprintf(stderr, "PacketAlias/GetEphemeralPort(): ");
643 fprintf(stderr, "could not find free port\n");
644 #endif
645
646 return(-1);
647}
648
b7080c8e
A
649static int
650GetNewPort(struct alias_link *link, int alias_port_param)
651{
652 int i;
653 int max_trials;
654 u_short port_sys;
655 u_short port_net;
656
f47db663
A
657 if (alias_port_param == GET_ALIAS_EPHEMERAL_PORT)
658 return GetEphemeralPort(link);
659
b7080c8e
A
660/*
661 Description of alias_port_param for GetNewPort(). When
662 this parameter is zero or positive, it precisely specifies
663 the port number. GetNewPort() will return this number
664 without check that it is in use.
665
7ba0088d 666 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
b7080c8e
A
667 selected port number.
668*/
b7080c8e
A
669 if (alias_port_param == GET_ALIAS_PORT)
670 {
671 /*
672 * The aliasing port is automatically selected
673 * by one of two methods below:
674 */
675 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
676
677 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
678 {
679 /*
7ba0088d 680 * When the PKT_ALIAS_SAME_PORTS option is
b7080c8e
A
681 * chosen, the first try will be the
682 * actual source port. If this is already
683 * in use, the remainder of the trials
684 * will be random.
685 */
686 port_net = link->src_port;
687 port_sys = ntohs(port_net);
688 }
689 else
690 {
691 /* First trial and all subsequent are random. */
692 port_sys = random() & ALIAS_PORT_MASK;
693 port_sys += ALIAS_PORT_BASE;
694 port_net = htons(port_sys);
695 }
696 }
697 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
698 {
699 link->alias_port = (u_short) alias_port_param;
700 return(0);
701 }
702 else
703 {
704#ifdef DEBUG
705 fprintf(stderr, "PacketAlias/GetNewPort(): ");
706 fprintf(stderr, "input parameter error\n");
707#endif
708 return(-1);
709 }
710
711
712/* Port number search */
713 for (i=0; i<max_trials; i++)
714 {
715 int go_ahead;
716 struct alias_link *search_result;
717
718 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
719 link->dst_port, port_net,
720 link->link_type, 0);
721
722 if (search_result == NULL)
723 go_ahead = 1;
724 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
725 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
726 go_ahead = 1;
727 else
728 go_ahead = 0;
729
730 if (go_ahead)
731 {
7ba0088d
A
732 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS)
733 && (link->flags & LINK_PARTIALLY_SPECIFIED)
734 && ((link->link_type == LINK_TCP) ||
735 (link->link_type == LINK_UDP)))
b7080c8e
A
736 {
737 if (GetSocket(port_net, &link->sockfd, link->link_type))
738 {
739 link->alias_port = port_net;
740 return(0);
741 }
742 }
743 else
744 {
745 link->alias_port = port_net;
746 return(0);
747 }
748 }
749
750 port_sys = random() & ALIAS_PORT_MASK;
751 port_sys += ALIAS_PORT_BASE;
752 port_net = htons(port_sys);
753 }
b7080c8e
A
754#ifdef DEBUG
755 fprintf(stderr, "PacketAlias/GetnewPort(): ");
756 fprintf(stderr, "could not find free port\n");
757#endif
758
759 return(-1);
760}
761
762
763static u_short
764GetSocket(u_short port_net, int *sockfd, int link_type)
765{
766 int err;
767 int sock;
768 struct sockaddr_in sock_addr;
769
770 if (link_type == LINK_TCP)
771 sock = socket(AF_INET, SOCK_STREAM, 0);
772 else if (link_type == LINK_UDP)
773 sock = socket(AF_INET, SOCK_DGRAM, 0);
774 else
775 {
776#ifdef DEBUG
777 fprintf(stderr, "PacketAlias/GetSocket(): ");
778 fprintf(stderr, "incorrect link type\n");
779#endif
780 return(0);
781 }
782
783 if (sock < 0)
784 {
785#ifdef DEBUG
786 fprintf(stderr, "PacketAlias/GetSocket(): ");
787 fprintf(stderr, "socket() error %d\n", *sockfd);
788#endif
789 return(0);
790 }
791
792 sock_addr.sin_family = AF_INET;
793 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
794 sock_addr.sin_port = port_net;
795
796 err = bind(sock,
797 (struct sockaddr *) &sock_addr,
798 sizeof(sock_addr));
799 if (err == 0)
800 {
801 sockCount++;
802 *sockfd = sock;
803 return(1);
804 }
805 else
806 {
807 close(sock);
808 return(0);
809 }
810}
811
812
7ba0088d
A
813/* FindNewPortGroup() returns a base port number for an available
814 range of contiguous port numbers. Note that if a port number
815 is already in use, that does not mean that it cannot be used by
816 another link concurrently. This is because FindNewPortGroup()
817 looks for unused triplets: (dest addr, dest port, alias port). */
818
819int
820FindNewPortGroup(struct in_addr dst_addr,
821 struct in_addr alias_addr,
822 u_short src_port,
823 u_short dst_port,
824 u_short port_count,
825 u_char proto,
826 u_char align)
827{
828 int i, j;
829 int max_trials;
830 u_short port_sys;
831 int link_type;
832
833 /*
834 * Get link_type from protocol
835 */
836
837 switch (proto)
838 {
839 case IPPROTO_UDP:
840 link_type = LINK_UDP;
841 break;
842 case IPPROTO_TCP:
843 link_type = LINK_TCP;
844 break;
845 default:
846 return (0);
847 break;
848 }
849
850 /*
851 * The aliasing port is automatically selected
852 * by one of two methods below:
853 */
854 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
855
856 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
857 /*
858 * When the ALIAS_SAME_PORTS option is
859 * chosen, the first try will be the
860 * actual source port. If this is already
861 * in use, the remainder of the trials
862 * will be random.
863 */
864 port_sys = ntohs(src_port);
865
866 } else {
867
868 /* First trial and all subsequent are random. */
869 if (align == FIND_EVEN_ALIAS_BASE)
870 port_sys = random() & ALIAS_PORT_MASK_EVEN;
871 else
872 port_sys = random() & ALIAS_PORT_MASK;
873
874 port_sys += ALIAS_PORT_BASE;
875 }
876
877/* Port number search */
878 for (i = 0; i < max_trials; i++) {
879
880 struct alias_link *search_result;
881
882 for (j = 0; j < port_count; j++)
883 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr,
884 dst_port, htons(port_sys + j),
885 link_type, 0)))
886 break;
887
888 /* Found a good range, return base */
889 if (j == port_count)
890 return (htons(port_sys));
891
892 /* Find a new base to try */
893 if (align == FIND_EVEN_ALIAS_BASE)
894 port_sys = random() & ALIAS_PORT_MASK_EVEN;
895 else
896 port_sys = random() & ALIAS_PORT_MASK;
897
898 port_sys += ALIAS_PORT_BASE;
899 }
900
901#ifdef DEBUG
902 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
903 fprintf(stderr, "could not find free port(s)\n");
904#endif
905
906 return(0);
907}
908
b7080c8e
A
909static void
910CleanupAliasData(void)
911{
912 struct alias_link *link;
913 int i, icount;
914
915 icount = 0;
916 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
917 {
7ba0088d 918 link = LIST_FIRST(&linkTableOut[i]);
b7080c8e
A
919 while (link != NULL)
920 {
921 struct alias_link *link_next;
7ba0088d 922 link_next = LIST_NEXT(link, list_out);
b7080c8e
A
923 icount++;
924 DeleteLink(link);
925 link = link_next;
926 }
927 }
928
929 cleanupIndex =0;
930}
931
932
933static void
934IncrementalCleanup(void)
935{
936 int icount;
937 struct alias_link *link;
938
939 icount = 0;
7ba0088d 940 link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
b7080c8e
A
941 while (link != NULL)
942 {
943 int idelta;
944 struct alias_link *link_next;
945
7ba0088d 946 link_next = LIST_NEXT(link, list_out);
b7080c8e
A
947 idelta = timeStamp - link->timestamp;
948 switch (link->link_type)
949 {
b7080c8e
A
950 case LINK_TCP:
951 if (idelta > link->expire_time)
952 {
953 struct tcp_dat *tcp_aux;
954
955 tcp_aux = link->data.tcp;
956 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
957 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
958 {
959 DeleteLink(link);
960 icount++;
961 }
962 }
963 break;
7ba0088d
A
964 default:
965 if (idelta > link->expire_time)
966 {
967 DeleteLink(link);
968 icount++;
969 }
970 break;
b7080c8e
A
971 }
972 link = link_next;
973 }
974
975 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
976 cleanupIndex = 0;
977}
978
7ba0088d 979static void
b7080c8e
A
980DeleteLink(struct alias_link *link)
981{
b7080c8e
A
982
983/* Don't do anything if the link is marked permanent */
984 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
985 return;
986
987#ifndef NO_FW_PUNCH
7ba0088d 988/* Delete associated firewall hole, if any */
b7080c8e
A
989 ClearFWHole(link);
990#endif
991
7ba0088d
A
992/* Free memory allocated for LSNAT server pool */
993 if (link->server != NULL) {
994 struct server *head, *curr, *next;
b7080c8e 995
7ba0088d
A
996 head = curr = link->server;
997 do {
998 next = curr->next;
999 free(curr);
1000 } while ((curr = next) != head);
1001 }
b7080c8e 1002
7ba0088d
A
1003/* Adjust output table pointers */
1004 LIST_REMOVE(link, list_out);
b7080c8e
A
1005
1006/* Adjust input table pointers */
7ba0088d 1007 LIST_REMOVE(link, list_in);
b7080c8e
A
1008
1009/* Close socket, if one has been allocated */
1010 if (link->sockfd != -1)
1011 {
1012 sockCount--;
1013 close(link->sockfd);
1014 }
1015
1016/* Link-type dependent cleanup */
1017 switch(link->link_type)
1018 {
1019 case LINK_ICMP:
1020 icmpLinkCount--;
1021 break;
1022 case LINK_UDP:
1023 udpLinkCount--;
1024 break;
1025 case LINK_TCP:
1026 tcpLinkCount--;
7ba0088d
A
1027 free(link->data.tcp);
1028 break;
1029 case LINK_PPTP:
1030 pptpLinkCount--;
b7080c8e
A
1031 break;
1032 case LINK_FRAGMENT_ID:
1033 fragmentIdLinkCount--;
1034 break;
1035 case LINK_FRAGMENT_PTR:
1036 fragmentPtrLinkCount--;
1037 if (link->data.frag_ptr != NULL)
1038 free(link->data.frag_ptr);
1039 break;
7ba0088d
A
1040 case LINK_ADDR:
1041 break;
1042 default:
1043 protoLinkCount--;
1044 break;
b7080c8e
A
1045 }
1046
ac2f15b3
A
1047#ifdef DEBUG
1048 if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
1049 !IN_MULTICAST(link->src_addr.s_addr) &&
1050 !IN_MULTICAST(link->dst_addr.s_addr))
b7080c8e 1051 {
ac2f15b3
A
1052 char src[16];
1053 char dst[16];
1054 char alias[16];
1055 char *proto;
1056 switch(link->link_type)
1057 {
1058 case LINK_TCP:
1059 proto = " [TCP]";
1060 break;
1061 case LINK_UDP:
1062 proto = " [UDP]";
1063 break;
1064 default:
1065 proto = "";
1066 }
1067 fprintf(monitorFile, "Deleted%s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1068 proto,
1069 inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port,
1070 inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port,
1071 inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port,
1072 dst, link->dst_port);
1073 fflush(monitorFile);
b7080c8e 1074 }
ac2f15b3
A
1075#else
1076 if (packetAliasMode & PKT_ALIAS_LOG)
1077 ShowAliasStats();
1078#endif
1079
1080/* Free memory */
1081 free(link);
b7080c8e
A
1082}
1083
1084
1085static struct alias_link *
1086AddLink(struct in_addr src_addr,
1087 struct in_addr dst_addr,
1088 struct in_addr alias_addr,
1089 u_short src_port,
1090 u_short dst_port,
1091 int alias_port_param, /* if less than zero, alias */
1092 int link_type) /* port will be automatically */
1093{ /* chosen. If greater than */
1094 u_int start_point; /* zero, equal to alias port */
1095 struct alias_link *link;
b7080c8e
A
1096
1097 link = malloc(sizeof(struct alias_link));
1098 if (link != NULL)
1099 {
b7080c8e
A
1100 /* Basic initialization */
1101 link->src_addr = src_addr;
1102 link->dst_addr = dst_addr;
1103 link->alias_addr = alias_addr;
7ba0088d 1104 link->proxy_addr.s_addr = INADDR_ANY;
b7080c8e
A
1105 link->src_port = src_port;
1106 link->dst_port = dst_port;
1107 link->proxy_port = 0;
7ba0088d 1108 link->server = NULL;
b7080c8e
A
1109 link->link_type = link_type;
1110 link->sockfd = -1;
1111 link->flags = 0;
1112 link->timestamp = timeStamp;
1113
1114 /* Expiration time */
1115 switch (link_type)
1116 {
1117 case LINK_ICMP:
1118 link->expire_time = ICMP_EXPIRE_TIME;
1119 break;
1120 case LINK_UDP:
ac2f15b3
A
1121 if (dst_addr.s_addr == 0 && dst_port == 0)
1122 link->expire_time = UDP_EXPIRE_TIME * 5;
1123 else
1124 link->expire_time = UDP_EXPIRE_TIME;
b7080c8e
A
1125 break;
1126 case LINK_TCP:
1127 link->expire_time = TCP_EXPIRE_INITIAL;
1128 break;
7ba0088d
A
1129 case LINK_PPTP:
1130 link->flags |= LINK_PERMANENT; /* no timeout. */
1131 break;
b7080c8e
A
1132 case LINK_FRAGMENT_ID:
1133 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1134 break;
1135 case LINK_FRAGMENT_PTR:
1136 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1137 break;
7ba0088d
A
1138 case LINK_ADDR:
1139 break;
1140 default:
1141 link->expire_time = PROTO_EXPIRE_TIME;
1142 break;
b7080c8e
A
1143 }
1144
1145 /* Determine alias flags */
7ba0088d 1146 if (dst_addr.s_addr == INADDR_ANY)
b7080c8e
A
1147 link->flags |= LINK_UNKNOWN_DEST_ADDR;
1148 if (dst_port == 0)
1149 link->flags |= LINK_UNKNOWN_DEST_PORT;
1150
1151 /* Determine alias port */
1152 if (GetNewPort(link, alias_port_param) != 0)
1153 {
1154 free(link);
1155 return(NULL);
1156 }
b7080c8e
A
1157 /* Link-type dependent initialization */
1158 switch(link_type)
1159 {
1160 struct tcp_dat *aux_tcp;
1161
1162 case LINK_ICMP:
1163 icmpLinkCount++;
1164 break;
1165 case LINK_UDP:
1166 udpLinkCount++;
1167 break;
1168 case LINK_TCP:
1169 aux_tcp = malloc(sizeof(struct tcp_dat));
b7080c8e
A
1170 if (aux_tcp != NULL)
1171 {
1172 int i;
1173
1174 tcpLinkCount++;
1175 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1176 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1177 aux_tcp->state.index = 0;
1178 aux_tcp->state.ack_modified = 0;
1179 for (i=0; i<N_LINK_TCP_DATA; i++)
1180 aux_tcp->ack[i].active = 0;
1181 aux_tcp->fwhole = -1;
7ba0088d 1182 link->data.tcp = aux_tcp;
b7080c8e
A
1183 }
1184 else
1185 {
1186#ifdef DEBUG
1187 fprintf(stderr, "PacketAlias/AddLink: ");
1188 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1189#endif
7ba0088d
A
1190 free(link);
1191 return (NULL);
b7080c8e
A
1192 }
1193 break;
7ba0088d
A
1194 case LINK_PPTP:
1195 pptpLinkCount++;
1196 break;
b7080c8e
A
1197 case LINK_FRAGMENT_ID:
1198 fragmentIdLinkCount++;
1199 break;
1200 case LINK_FRAGMENT_PTR:
1201 fragmentPtrLinkCount++;
1202 break;
7ba0088d
A
1203 case LINK_ADDR:
1204 break;
1205 default:
1206 protoLinkCount++;
1207 break;
b7080c8e 1208 }
7ba0088d
A
1209
1210 /* Set up pointers for output lookup table */
1211 start_point = StartPointOut(src_addr, dst_addr,
1212 src_port, dst_port, link_type);
1213 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1214
1215 /* Set up pointers for input lookup table */
1216 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1217 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
b7080c8e
A
1218 }
1219 else
1220 {
1221#ifdef DEBUG
1222 fprintf(stderr, "PacketAlias/AddLink(): ");
1223 fprintf(stderr, "malloc() call failed.\n");
1224#endif
1225 }
1226
ac2f15b3
A
1227#ifdef DEBUG
1228 if ((packetAliasMode & PKT_ALIAS_LOG) != 0 &&
1229 !IN_MULTICAST(link->src_addr.s_addr) &&
1230 !IN_MULTICAST(link->dst_addr.s_addr))
b7080c8e 1231 {
ac2f15b3
A
1232 char src[16];
1233 char dst[16];
1234 char alias[16];
1235 char *proto;
1236 switch(link->link_type)
1237 {
1238 case LINK_TCP:
1239 proto = " [TCP]";
1240 break;
1241 case LINK_UDP:
1242 proto = " [UDP]";
1243 break;
1244 default:
1245 proto = "";
1246 }
1247 fprintf(monitorFile, "Added %s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1248 proto,
1249 inet_ntop(AF_INET, &link->src_addr, src, sizeof(src)), link->src_port,
1250 inet_ntop(AF_INET, &link->dst_addr, dst, sizeof(dst)), link->dst_port,
1251 inet_ntop(AF_INET, &link->alias_addr, alias, sizeof(alias)), link->alias_port,
1252 dst, link->dst_port);
b7080c8e 1253 }
ac2f15b3
A
1254#else
1255 if (packetAliasMode & PKT_ALIAS_LOG)
1256 ShowAliasStats();
1257#endif
b7080c8e
A
1258
1259 return(link);
1260}
1261
1262static struct alias_link *
1263ReLink(struct alias_link *old_link,
1264 struct in_addr src_addr,
1265 struct in_addr dst_addr,
1266 struct in_addr alias_addr,
1267 u_short src_port,
1268 u_short dst_port,
1269 int alias_port_param, /* if less than zero, alias */
1270 int link_type) /* port will be automatically */
1271{ /* chosen. If greater than */
1272 struct alias_link *new_link; /* zero, equal to alias port */
1273
1274 new_link = AddLink(src_addr, dst_addr, alias_addr,
1275 src_port, dst_port, alias_port_param,
1276 link_type);
1277#ifndef NO_FW_PUNCH
1278 if (new_link != NULL &&
1279 old_link->link_type == LINK_TCP &&
b7080c8e
A
1280 old_link->data.tcp->fwhole > 0) {
1281 PunchFWHole(new_link);
1282 }
1283#endif
ac2f15b3
A
1284 if ((old_link->flags & LINK_CONE) == 0)
1285 DeleteLink(old_link);
b7080c8e
A
1286 return new_link;
1287}
1288
1289static struct alias_link *
7ba0088d 1290_FindLinkOut(struct in_addr src_addr,
b7080c8e
A
1291 struct in_addr dst_addr,
1292 u_short src_port,
1293 u_short dst_port,
7ba0088d
A
1294 int link_type,
1295 int replace_partial_links)
b7080c8e
A
1296{
1297 u_int i;
1298 struct alias_link *link;
1299
b7080c8e 1300 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
7ba0088d 1301 LIST_FOREACH(link, &linkTableOut[i], list_out)
b7080c8e
A
1302 {
1303 if (link->src_addr.s_addr == src_addr.s_addr
7ba0088d 1304 && link->server == NULL
b7080c8e
A
1305 && link->dst_addr.s_addr == dst_addr.s_addr
1306 && link->dst_port == dst_port
1307 && link->src_port == src_port
1308 && link->link_type == link_type)
1309 {
1310 link->timestamp = timeStamp;
1311 break;
1312 }
7ba0088d
A
1313 }
1314
1315/* Search for partially specified links. */
1316 if (link == NULL && replace_partial_links)
1317 {
1318 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1319 {
1320 link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1321 link_type, 0);
1322 if (link == NULL)
1323 link = _FindLinkOut(src_addr, nullAddress, src_port,
1324 dst_port, link_type, 0);
1325 }
1326 if (link == NULL &&
1327 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1328 {
1329 link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1330 link_type, 0);
1331 }
1332 if (link != NULL)
1333 {
1334 link = ReLink(link,
1335 src_addr, dst_addr, link->alias_addr,
1336 src_port, dst_port, link->alias_port,
1337 link_type);
1338 }
b7080c8e
A
1339 }
1340
1341 return(link);
1342}
1343
7ba0088d
A
1344static struct alias_link *
1345FindLinkOut(struct in_addr src_addr,
1346 struct in_addr dst_addr,
1347 u_short src_port,
1348 u_short dst_port,
1349 int link_type,
1350 int replace_partial_links)
1351{
1352 struct alias_link *link;
b7080c8e 1353
7ba0088d
A
1354 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1355 link_type, replace_partial_links);
1356
1357 if (link == NULL)
1358 {
1359 /* The following allows permanent links to be
1360 specified as using the default source address
1361 (i.e. device interface address) without knowing
1362 in advance what that address is. */
1363 if (aliasAddress.s_addr != 0 &&
1364 src_addr.s_addr == aliasAddress.s_addr)
1365 {
1366 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1367 link_type, replace_partial_links);
1368 }
1369 }
1370
1371 return(link);
1372}
1373
1374
1375static struct alias_link *
1376_FindLinkIn(struct in_addr dst_addr,
b7080c8e
A
1377 struct in_addr alias_addr,
1378 u_short dst_port,
1379 u_short alias_port,
1380 int link_type,
1381 int replace_partial_links)
1382{
1383 int flags_in;
1384 u_int start_point;
1385 struct alias_link *link;
1386 struct alias_link *link_fully_specified;
1387 struct alias_link *link_unknown_all;
1388 struct alias_link *link_unknown_dst_addr;
1389 struct alias_link *link_unknown_dst_port;
1390
1391/* Initialize pointers */
1392 link_fully_specified = NULL;
1393 link_unknown_all = NULL;
1394 link_unknown_dst_addr = NULL;
1395 link_unknown_dst_port = NULL;
1396
1397/* If either the dest addr or port is unknown, the search
1398 loop will have to know about this. */
1399
1400 flags_in = 0;
7ba0088d 1401 if (dst_addr.s_addr == INADDR_ANY)
b7080c8e
A
1402 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1403 if (dst_port == 0)
1404 flags_in |= LINK_UNKNOWN_DEST_PORT;
1405
b7080c8e
A
1406/* Search loop */
1407 start_point = StartPointIn(alias_addr, alias_port, link_type);
7ba0088d 1408 LIST_FOREACH(link, &linkTableIn[start_point], list_in)
b7080c8e
A
1409 {
1410 int flags;
1411
1412 flags = flags_in | link->flags;
1413 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1414 {
1415 if (link->alias_addr.s_addr == alias_addr.s_addr
1416 && link->alias_port == alias_port
1417 && link->dst_addr.s_addr == dst_addr.s_addr
1418 && link->dst_port == dst_port
1419 && link->link_type == link_type)
1420 {
1421 link_fully_specified = link;
1422 break;
1423 }
1424 }
1425 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1426 && (flags & LINK_UNKNOWN_DEST_PORT))
1427 {
1428 if (link->alias_addr.s_addr == alias_addr.s_addr
1429 && link->alias_port == alias_port
1430 && link->link_type == link_type)
1431 {
1432 if (link_unknown_all == NULL)
1433 link_unknown_all = link;
1434 }
1435 }
1436 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1437 {
1438 if (link->alias_addr.s_addr == alias_addr.s_addr
1439 && link->alias_port == alias_port
1440 && link->link_type == link_type
1441 && link->dst_port == dst_port)
1442 {
1443 if (link_unknown_dst_addr == NULL)
1444 link_unknown_dst_addr = link;
1445 }
1446 }
1447 else if (flags & LINK_UNKNOWN_DEST_PORT)
1448 {
1449 if (link->alias_addr.s_addr == alias_addr.s_addr
1450 && link->alias_port == alias_port
1451 && link->link_type == link_type
1452 && link->dst_addr.s_addr == dst_addr.s_addr)
1453 {
1454 if (link_unknown_dst_port == NULL)
1455 link_unknown_dst_port = link;
1456 }
1457 }
b7080c8e
A
1458 }
1459
1460
1461
1462 if (link_fully_specified != NULL)
1463 {
7ba0088d
A
1464 link_fully_specified->timestamp = timeStamp;
1465 link = link_fully_specified;
b7080c8e
A
1466 }
1467 else if (link_unknown_dst_port != NULL)
7ba0088d 1468 link = link_unknown_dst_port;
b7080c8e 1469 else if (link_unknown_dst_addr != NULL)
7ba0088d 1470 link = link_unknown_dst_addr;
b7080c8e 1471 else if (link_unknown_all != NULL)
7ba0088d
A
1472 link = link_unknown_all;
1473 else
1474 return (NULL);
1475
1476 if (replace_partial_links &&
1477 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
b7080c8e 1478 {
7ba0088d
A
1479 struct in_addr src_addr;
1480 u_short src_port;
1481
1482 if (link->server != NULL) { /* LSNAT link */
1483 src_addr = link->server->addr;
1484 src_port = link->server->port;
1485 link->server = link->server->next;
1486 } else {
1487 src_addr = link->src_addr;
1488 src_port = link->src_port;
1489 }
1490
1491 link = ReLink(link,
1492 src_addr, dst_addr, alias_addr,
1493 src_port, dst_port, alias_port,
1494 link_type);
b7080c8e 1495 }
7ba0088d
A
1496
1497 return (link);
1498}
1499
1500static struct alias_link *
1501FindLinkIn(struct in_addr dst_addr,
1502 struct in_addr alias_addr,
1503 u_short dst_port,
1504 u_short alias_port,
1505 int link_type,
1506 int replace_partial_links)
1507{
1508 struct alias_link *link;
1509
1510 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1511 link_type, replace_partial_links);
1512
1513 if (link == NULL)
b7080c8e 1514 {
7ba0088d
A
1515 /* The following allows permanent links to be
1516 specified as using the default aliasing address
1517 (i.e. device interface address) without knowing
1518 in advance what that address is. */
1519 if (aliasAddress.s_addr != 0 &&
1520 alias_addr.s_addr == aliasAddress.s_addr)
1521 {
1522 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1523 link_type, replace_partial_links);
1524 }
b7080c8e 1525 }
7ba0088d
A
1526
1527 return(link);
b7080c8e
A
1528}
1529
1530
1531
1532
1533/* External routines for finding/adding links
1534
1535-- "external" means outside alias_db.c, but within alias*.c --
1536
1537 FindIcmpIn(), FindIcmpOut()
1538 FindFragmentIn1(), FindFragmentIn2()
1539 AddFragmentPtrLink(), FindFragmentPtr()
7ba0088d 1540 FindProtoIn(), FindProtoOut()
b7080c8e 1541 FindUdpTcpIn(), FindUdpTcpOut()
7ba0088d
A
1542 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1543 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
b7080c8e
A
1544 FindOriginalAddress(), FindAliasAddress()
1545
1546(prototypes in alias_local.h)
1547*/
1548
1549
1550struct alias_link *
1551FindIcmpIn(struct in_addr dst_addr,
1552 struct in_addr alias_addr,
7ba0088d
A
1553 u_short id_alias,
1554 int create)
b7080c8e 1555{
7ba0088d
A
1556 struct alias_link *link;
1557
1558 link = FindLinkIn(dst_addr, alias_addr,
b7080c8e
A
1559 NO_DEST_PORT, id_alias,
1560 LINK_ICMP, 0);
7ba0088d
A
1561 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1562 {
1563 struct in_addr target_addr;
1564
1565 target_addr = FindOriginalAddress(alias_addr);
1566 link = AddLink(target_addr, dst_addr, alias_addr,
1567 id_alias, NO_DEST_PORT, id_alias,
1568 LINK_ICMP);
1569 }
1570
1571 return (link);
b7080c8e
A
1572}
1573
1574
1575struct alias_link *
1576FindIcmpOut(struct in_addr src_addr,
1577 struct in_addr dst_addr,
7ba0088d
A
1578 u_short id,
1579 int create)
b7080c8e
A
1580{
1581 struct alias_link * link;
1582
1583 link = FindLinkOut(src_addr, dst_addr,
1584 id, NO_DEST_PORT,
7ba0088d
A
1585 LINK_ICMP, 0);
1586 if (link == NULL && create)
b7080c8e
A
1587 {
1588 struct in_addr alias_addr;
1589
1590 alias_addr = FindAliasAddress(src_addr);
1591 link = AddLink(src_addr, dst_addr, alias_addr,
1592 id, NO_DEST_PORT, GET_ALIAS_ID,
1593 LINK_ICMP);
1594 }
1595
1596 return(link);
1597}
1598
1599
1600struct alias_link *
1601FindFragmentIn1(struct in_addr dst_addr,
1602 struct in_addr alias_addr,
1603 u_short ip_id)
1604{
1605 struct alias_link *link;
1606
1607 link = FindLinkIn(dst_addr, alias_addr,
1608 NO_DEST_PORT, ip_id,
1609 LINK_FRAGMENT_ID, 0);
1610
1611 if (link == NULL)
1612 {
1613 link = AddLink(nullAddress, dst_addr, alias_addr,
1614 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1615 LINK_FRAGMENT_ID);
1616 }
1617
1618 return(link);
1619}
1620
1621
1622struct alias_link *
1623FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1624 struct in_addr alias_addr, /* is not found. */
1625 u_short ip_id)
1626{
1627 return FindLinkIn(dst_addr, alias_addr,
1628 NO_DEST_PORT, ip_id,
1629 LINK_FRAGMENT_ID, 0);
1630}
1631
1632
1633struct alias_link *
1634AddFragmentPtrLink(struct in_addr dst_addr,
1635 u_short ip_id)
1636{
1637 return AddLink(nullAddress, dst_addr, nullAddress,
1638 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1639 LINK_FRAGMENT_PTR);
1640}
1641
1642
1643struct alias_link *
1644FindFragmentPtr(struct in_addr dst_addr,
1645 u_short ip_id)
1646{
1647 return FindLinkIn(dst_addr, nullAddress,
1648 NO_DEST_PORT, ip_id,
1649 LINK_FRAGMENT_PTR, 0);
1650}
1651
1652
7ba0088d
A
1653struct alias_link *
1654FindProtoIn(struct in_addr dst_addr,
1655 struct in_addr alias_addr,
1656 u_char proto)
1657{
1658 struct alias_link *link;
1659
1660 link = FindLinkIn(dst_addr, alias_addr,
1661 NO_DEST_PORT, 0,
1662 proto, 1);
1663
1664 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1665 {
1666 struct in_addr target_addr;
1667
1668 target_addr = FindOriginalAddress(alias_addr);
1669 link = AddLink(target_addr, dst_addr, alias_addr,
1670 NO_SRC_PORT, NO_DEST_PORT, 0,
1671 proto);
1672 }
1673
1674 return (link);
1675}
1676
1677
1678struct alias_link *
1679FindProtoOut(struct in_addr src_addr,
1680 struct in_addr dst_addr,
1681 u_char proto)
1682{
1683 struct alias_link *link;
1684
1685 link = FindLinkOut(src_addr, dst_addr,
1686 NO_SRC_PORT, NO_DEST_PORT,
1687 proto, 1);
1688
1689 if (link == NULL)
1690 {
1691 struct in_addr alias_addr;
1692
1693 alias_addr = FindAliasAddress(src_addr);
1694 link = AddLink(src_addr, dst_addr, alias_addr,
1695 NO_SRC_PORT, NO_DEST_PORT, 0,
1696 proto);
1697 }
1698
1699 return (link);
1700}
1701
1702
b7080c8e
A
1703struct alias_link *
1704FindUdpTcpIn(struct in_addr dst_addr,
1705 struct in_addr alias_addr,
1706 u_short dst_port,
1707 u_short alias_port,
7ba0088d
A
1708 u_char proto,
1709 int create)
b7080c8e
A
1710{
1711 int link_type;
1712 struct alias_link *link;
1713
1714 switch (proto)
1715 {
1716 case IPPROTO_UDP:
1717 link_type = LINK_UDP;
1718 break;
1719 case IPPROTO_TCP:
1720 link_type = LINK_TCP;
1721 break;
1722 default:
1723 return NULL;
1724 break;
1725 }
1726
1727 link = FindLinkIn(dst_addr, alias_addr,
1728 dst_port, alias_port,
7ba0088d 1729 link_type, create);
b7080c8e 1730
7ba0088d 1731 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
b7080c8e
A
1732 {
1733 struct in_addr target_addr;
1734
1735 target_addr = FindOriginalAddress(alias_addr);
1736 link = AddLink(target_addr, dst_addr, alias_addr,
1737 alias_port, dst_port, alias_port,
1738 link_type);
1739 }
1740
1741 return(link);
1742}
1743
1744
1745struct alias_link *
1746FindUdpTcpOut(struct in_addr src_addr,
1747 struct in_addr dst_addr,
1748 u_short src_port,
1749 u_short dst_port,
7ba0088d
A
1750 u_char proto,
1751 int create)
b7080c8e
A
1752{
1753 int link_type;
1754 struct alias_link *link;
1755
1756 switch (proto)
1757 {
1758 case IPPROTO_UDP:
1759 link_type = LINK_UDP;
1760 break;
1761 case IPPROTO_TCP:
1762 link_type = LINK_TCP;
1763 break;
1764 default:
1765 return NULL;
1766 break;
1767 }
1768
7ba0088d 1769 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
b7080c8e 1770
7ba0088d 1771 if (link == NULL && create)
b7080c8e
A
1772 {
1773 struct in_addr alias_addr;
ac2f15b3
A
1774 struct in_addr dst_addr2 = dst_addr;
1775 u_short dst_port2 = dst_port;
b7080c8e
A
1776
1777 alias_addr = FindAliasAddress(src_addr);
ac2f15b3
A
1778
1779 if (iChatAVHack && link_type == LINK_UDP && dst_port == htons(5678)) {
1780 dst_addr2.s_addr = 0;
1781 dst_port2 = 0;
1782 }
1783 link = AddLink(src_addr, dst_addr2, alias_addr,
1784 src_port, dst_port2, GET_ALIAS_PORT,
b7080c8e 1785 link_type);
ac2f15b3
A
1786 if (link != NULL &&
1787 (link->flags & (LINK_UNKNOWN_DEST_ADDR | LINK_UNKNOWN_DEST_PORT)) != 0)
1788 {
1789 link->flags |= LINK_CONE;
1790 link = ReLink(link, link->src_addr, dst_addr, link->alias_addr,
1791 link->src_port, dst_port, link->alias_port, link_type);
1792 }
b7080c8e
A
1793 }
1794
1795 return(link);
1796}
1797
1798
7ba0088d
A
1799struct alias_link *
1800AddPptp(struct in_addr src_addr,
1801 struct in_addr dst_addr,
1802 struct in_addr alias_addr,
1803 u_int16_t src_call_id)
1804{
1805 struct alias_link *link;
1806
1807 link = AddLink(src_addr, dst_addr, alias_addr,
1808 src_call_id, 0, GET_ALIAS_PORT,
1809 LINK_PPTP);
1810
1811 return (link);
1812}
1813
1814
1815struct alias_link *
1816FindPptpOutByCallId(struct in_addr src_addr,
1817 struct in_addr dst_addr,
1818 u_int16_t src_call_id)
1819{
1820 u_int i;
1821 struct alias_link *link;
1822
1823 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1824 LIST_FOREACH(link, &linkTableOut[i], list_out)
1825 if (link->link_type == LINK_PPTP &&
1826 link->src_addr.s_addr == src_addr.s_addr &&
1827 link->dst_addr.s_addr == dst_addr.s_addr &&
1828 link->src_port == src_call_id)
1829 break;
1830
1831 return (link);
1832}
1833
1834
1835struct alias_link *
1836FindPptpOutByPeerCallId(struct in_addr src_addr,
1837 struct in_addr dst_addr,
1838 u_int16_t dst_call_id)
1839{
1840 u_int i;
1841 struct alias_link *link;
1842
1843 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1844 LIST_FOREACH(link, &linkTableOut[i], list_out)
1845 if (link->link_type == LINK_PPTP &&
1846 link->src_addr.s_addr == src_addr.s_addr &&
1847 link->dst_addr.s_addr == dst_addr.s_addr &&
1848 link->dst_port == dst_call_id)
1849 break;
1850
1851 return (link);
1852}
1853
1854
1855struct alias_link *
1856FindPptpInByCallId(struct in_addr dst_addr,
1857 struct in_addr alias_addr,
1858 u_int16_t dst_call_id)
1859{
1860 u_int i;
1861 struct alias_link *link;
1862
1863 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1864 LIST_FOREACH(link, &linkTableIn[i], list_in)
1865 if (link->link_type == LINK_PPTP &&
1866 link->dst_addr.s_addr == dst_addr.s_addr &&
1867 link->alias_addr.s_addr == alias_addr.s_addr &&
1868 link->dst_port == dst_call_id)
1869 break;
1870
1871 return (link);
1872}
1873
1874
1875struct alias_link *
1876FindPptpInByPeerCallId(struct in_addr dst_addr,
1877 struct in_addr alias_addr,
1878 u_int16_t alias_call_id)
1879{
1880 struct alias_link *link;
1881
1882 link = FindLinkIn(dst_addr, alias_addr,
1883 0/* any */, alias_call_id,
1884 LINK_PPTP, 0);
1885
1886
1887 return (link);
1888}
1889
1890
1891struct alias_link *
1892FindRtspOut(struct in_addr src_addr,
1893 struct in_addr dst_addr,
1894 u_short src_port,
1895 u_short alias_port,
1896 u_char proto)
1897{
1898 int link_type;
1899 struct alias_link *link;
1900
1901 switch (proto)
1902 {
1903 case IPPROTO_UDP:
1904 link_type = LINK_UDP;
1905 break;
1906 case IPPROTO_TCP:
1907 link_type = LINK_TCP;
1908 break;
1909 default:
1910 return NULL;
1911 break;
1912 }
1913
1914 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1915
1916 if (link == NULL)
1917 {
1918 struct in_addr alias_addr;
1919
1920 alias_addr = FindAliasAddress(src_addr);
1921 link = AddLink(src_addr, dst_addr, alias_addr,
1922 src_port, 0, alias_port,
1923 link_type);
1924 }
1925
1926 return(link);
1927}
1928
1929
b7080c8e
A
1930struct in_addr
1931FindOriginalAddress(struct in_addr alias_addr)
1932{
1933 struct alias_link *link;
1934
1935 link = FindLinkIn(nullAddress, alias_addr,
1936 0, 0, LINK_ADDR, 0);
1937 if (link == NULL)
1938 {
1939 newDefaultLink = 1;
7ba0088d 1940 if (targetAddress.s_addr == INADDR_ANY)
b7080c8e 1941 return alias_addr;
7ba0088d
A
1942 else if (targetAddress.s_addr == INADDR_NONE)
1943 return aliasAddress;
1944 else
1945 return targetAddress;
b7080c8e
A
1946 }
1947 else
1948 {
7ba0088d
A
1949 if (link->server != NULL) { /* LSNAT link */
1950 struct in_addr src_addr;
1951
1952 src_addr = link->server->addr;
1953 link->server = link->server->next;
1954 return (src_addr);
1955 } else if (link->src_addr.s_addr == INADDR_ANY)
b7080c8e
A
1956 return aliasAddress;
1957 else
1958 return link->src_addr;
1959 }
1960}
1961
1962
1963struct in_addr
1964FindAliasAddress(struct in_addr original_addr)
1965{
1966 struct alias_link *link;
1967
1968 link = FindLinkOut(original_addr, nullAddress,
7ba0088d 1969 0, 0, LINK_ADDR, 0);
b7080c8e
A
1970 if (link == NULL)
1971 {
1972 return aliasAddress;
1973 }
1974 else
1975 {
7ba0088d 1976 if (link->alias_addr.s_addr == INADDR_ANY)
b7080c8e
A
1977 return aliasAddress;
1978 else
1979 return link->alias_addr;
1980 }
1981}
1982
2b484d24
A
1983/* FindAliasPortOut */
1984/* external routine for NatPortMap */
1985/* return alias port for the src_addr,dst_addr,src_port and proto */
1986/* if one doesn't existed, create a mapping with providing pub_port if it's not 0 */
1987/* delete mapping if addmapping is not true */
1988int
1989FindAliasPortOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short pub_port, u_char proto, int lifetime, char addmapping)
1990{
1991 u_int i;
1992 struct alias_link *link;
1993 int link_type;
1994
1995 switch (proto)
1996 {
1997 case IPPROTO_UDP:
1998 link_type = LINK_UDP;
1999 break;
2000 case IPPROTO_TCP:
2001 link_type = LINK_TCP;
2002 break;
2003 default:
f47db663 2004 return 0;
2b484d24
A
2005 break;
2006 }
2007
2008#ifdef DEBUG
2009 {
f47db663 2010 int icount = 0;
2b484d24 2011
f47db663
A
2012 printf("FindAliasPortOut:: srcaddr= %s:%u, ",
2013 inet_ntoa(src_addr), ntohs(src_port));
2014 printf("dstadd= %s:%u link_type= %d, lifetime= %d\n",
2015 inet_ntoa(dst_addr), ntohs(pub_port), link_type, lifetime);
2b484d24
A
2016
2017 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2018 {
2019 link = LIST_FIRST(&linkTableOut[i]);
2020 while (link != NULL)
2021 {
2022 struct alias_link *link_next;
f47db663
A
2023 char src_str[32], dst_str[32], alias_str[32];
2024
2025 snprintf(src_str, sizeof(src_str), "%s:%u",
2026 inet_ntoa(link->src_addr), ntohs(link->src_port));
2027 snprintf(dst_str, sizeof(dst_str), "%s:%u",
2028 inet_ntoa(link->dst_addr), ntohs(link->dst_port));
2029 snprintf(alias_str, sizeof(alias_str), "%s:%u",
2030 inet_ntoa(link->alias_addr), ntohs(link->alias_port));
2031
2032 printf(" linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d",
2033 i, icount, src_str, dst_str, alias_str,
2034 link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd);
2035
2b484d24
A
2036 link_next = LIST_NEXT(link, list_out);
2037 icount++;
2038 link = link_next;
2039 }
2040 }
2041
2042 }
2043#endif
2044
2045 i = StartPointOut(src_addr, dst_addr, src_port, 0, link_type);
2046#ifdef DEBUG
2047 printf("PORTMAP::StartPointOut returns %d\n", i);
2048#endif
2049 LIST_FOREACH(link, &linkTableOut[i], list_out)
2050 {
2051 if (link->src_addr.s_addr == src_addr.s_addr &&
2052 link->dst_addr.s_addr == dst_addr.s_addr &&
2053 link->src_port == src_port && link->link_type == link_type)
2054 break;
2055 }
2056
2057 if ( link == NULL && addmapping)
2058 {
2059 struct in_addr alias_addr;
2060#ifdef DEBUG
f47db663
A
2061 printf("PORTMAP:: cannot find mapping, adding mapping private port =%d, public port = %d\n",
2062 src_port, pub_port);
2b484d24
A
2063#endif
2064 /* address/port in not in list, create new mapping */
2065
2066 alias_addr = FindAliasAddress(src_addr);
2067 /* create new mapping */
2b484d24 2068 link = AddLink(src_addr, dst_addr, alias_addr,
f47db663 2069 src_port, 0, GET_ALIAS_EPHEMERAL_PORT,
2b484d24 2070 link_type);
f47db663 2071 if ( link != NULL ) {
2b484d24
A
2072 /* link was create, set new lifetime */
2073 SetExpire(link, lifetime);
f47db663
A
2074 /* Prevent link deletion when incoming connection arrive */
2075 link->flags |= LINK_CONE;
2076 }
2b484d24
A
2077 }
2078 if ( link )
2079 {
2080 if ( addmapping )
2081 return( GetAliasPort(link));
2082 else
2083 {
2084 SetExpire(link, 0); /* delete mapping */
2085 return 0;
2086 }
2087 }
2088
2089 return -1;
2090}
2091
b7080c8e
A
2092
2093/* External routines for getting or changing link data
2094 (external to alias_db.c, but internal to alias*.c)
2095
2096 SetFragmentData(), GetFragmentData()
2097 SetFragmentPtr(), GetFragmentPtr()
2098 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
2099 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
2100 GetOriginalPort(), GetAliasPort()
2101 SetAckModified(), GetAckModified()
2102 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
7ba0088d
A
2103 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
2104 SetDestCallId()
b7080c8e
A
2105*/
2106
2107
2108void
2109SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
2110{
2111 link->data.frag_addr = src_addr;
2112}
2113
2114
2115void
2116GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
2117{
2118 *src_addr = link->data.frag_addr;
2119}
2120
2121
2122void
2123SetFragmentPtr(struct alias_link *link, char *fptr)
2124{
2125 link->data.frag_ptr = fptr;
2126}
2127
2128
2129void
2130GetFragmentPtr(struct alias_link *link, char **fptr)
2131{
2132 *fptr = link->data.frag_ptr;
2133}
2134
2135
2136void
2137SetStateIn(struct alias_link *link, int state)
2138{
2139 /* TCP input state */
2140 switch (state) {
2141 case ALIAS_TCP_STATE_DISCONNECTED:
7ba0088d 2142 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
b7080c8e 2143 link->expire_time = TCP_EXPIRE_DEAD;
7ba0088d 2144 else
b7080c8e 2145 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
b7080c8e
A
2146 break;
2147 case ALIAS_TCP_STATE_CONNECTED:
7ba0088d
A
2148 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
2149 link->expire_time = TCP_EXPIRE_CONNECTED;
b7080c8e
A
2150 break;
2151 default:
2152 abort();
2153 }
7ba0088d 2154 link->data.tcp->state.in = state;
b7080c8e
A
2155}
2156
2157
2158void
2159SetStateOut(struct alias_link *link, int state)
2160{
2161 /* TCP output state */
2162 switch (state) {
2163 case ALIAS_TCP_STATE_DISCONNECTED:
7ba0088d 2164 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
b7080c8e 2165 link->expire_time = TCP_EXPIRE_DEAD;
7ba0088d 2166 else
b7080c8e 2167 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
b7080c8e
A
2168 break;
2169 case ALIAS_TCP_STATE_CONNECTED:
7ba0088d
A
2170 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
2171 link->expire_time = TCP_EXPIRE_CONNECTED;
b7080c8e
A
2172 break;
2173 default:
2174 abort();
2175 }
7ba0088d 2176 link->data.tcp->state.out = state;
b7080c8e
A
2177}
2178
2179
2180int
2181GetStateIn(struct alias_link *link)
2182{
2183 /* TCP input state */
2184 return link->data.tcp->state.in;
2185}
2186
2187
2188int
2189GetStateOut(struct alias_link *link)
2190{
2191 /* TCP output state */
2192 return link->data.tcp->state.out;
2193}
2194
2195
2196struct in_addr
2197GetOriginalAddress(struct alias_link *link)
2198{
7ba0088d 2199 if (link->src_addr.s_addr == INADDR_ANY)
b7080c8e
A
2200 return aliasAddress;
2201 else
2202 return(link->src_addr);
2203}
2204
2205
2206struct in_addr
2207GetDestAddress(struct alias_link *link)
2208{
2209 return(link->dst_addr);
2210}
2211
2212
2213struct in_addr
2214GetAliasAddress(struct alias_link *link)
2215{
7ba0088d 2216 if (link->alias_addr.s_addr == INADDR_ANY)
b7080c8e
A
2217 return aliasAddress;
2218 else
2219 return link->alias_addr;
2220}
2221
2222
2223struct in_addr
2224GetDefaultAliasAddress()
2225{
2226 return aliasAddress;
2227}
2228
2229
2230void
2231SetDefaultAliasAddress(struct in_addr alias_addr)
2232{
2233 aliasAddress = alias_addr;
2234}
2235
2236
2237u_short
2238GetOriginalPort(struct alias_link *link)
2239{
2240 return(link->src_port);
2241}
2242
2243
2244u_short
2245GetAliasPort(struct alias_link *link)
2246{
2247 return(link->alias_port);
2248}
2249
7ba0088d
A
2250#ifndef NO_FW_PUNCH
2251static u_short
b7080c8e
A
2252GetDestPort(struct alias_link *link)
2253{
2254 return(link->dst_port);
2255}
7ba0088d 2256#endif
b7080c8e
A
2257
2258void
2259SetAckModified(struct alias_link *link)
2260{
7ba0088d 2261/* Indicate that ACK numbers have been modified in a TCP connection */
b7080c8e
A
2262 link->data.tcp->state.ack_modified = 1;
2263}
2264
2265
2266struct in_addr
2267GetProxyAddress(struct alias_link *link)
2268{
2269 return link->proxy_addr;
2270}
2271
2272
2273void
2274SetProxyAddress(struct alias_link *link, struct in_addr addr)
2275{
2276 link->proxy_addr = addr;
2277}
2278
2279
2280u_short
2281GetProxyPort(struct alias_link *link)
2282{
2283 return link->proxy_port;
2284}
2285
2286
2287void
2288SetProxyPort(struct alias_link *link, u_short port)
2289{
2290 link->proxy_port = port;
2291}
2292
2293
2294int
2295GetAckModified(struct alias_link *link)
2296{
7ba0088d 2297/* See if ACK numbers have been modified */
b7080c8e
A
2298 return link->data.tcp->state.ack_modified;
2299}
2300
2301
2302int
2303GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2304{
2305/*
7ba0088d
A
2306Find out how much the ACK number has been altered for an incoming
2307TCP packet. To do this, a circular list of ACK numbers where the TCP
b7080c8e
A
2308packet size was altered is searched.
2309*/
2310
2311 int i;
2312 struct tcphdr *tc;
2313 int delta, ack_diff_min;
2314 u_long ack;
2315
2316 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2317 ack = tc->th_ack;
2318
2319 delta = 0;
2320 ack_diff_min = -1;
2321 for (i=0; i<N_LINK_TCP_DATA; i++)
2322 {
2323 struct ack_data_record x;
2324
2325 x = link->data.tcp->ack[i];
2326 if (x.active == 1)
2327 {
2328 int ack_diff;
2329
2330 ack_diff = SeqDiff(x.ack_new, ack);
2331 if (ack_diff >= 0)
2332 {
2333 if (ack_diff_min >= 0)
2334 {
2335 if (ack_diff < ack_diff_min)
2336 {
2337 delta = x.delta;
2338 ack_diff_min = ack_diff;
2339 }
2340 }
2341 else
2342 {
2343 delta = x.delta;
2344 ack_diff_min = ack_diff;
2345 }
2346 }
2347 }
2348 }
2349 return (delta);
2350}
2351
2352
2353int
2354GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2355{
2356/*
7ba0088d
A
2357Find out how much the sequence number has been altered for an outgoing
2358TCP packet. To do this, a circular list of ACK numbers where the TCP
b7080c8e
A
2359packet size was altered is searched.
2360*/
2361
2362 int i;
2363 struct tcphdr *tc;
2364 int delta, seq_diff_min;
2365 u_long seq;
2366
2367 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2368 seq = tc->th_seq;
2369
2370 delta = 0;
2371 seq_diff_min = -1;
2372 for (i=0; i<N_LINK_TCP_DATA; i++)
2373 {
2374 struct ack_data_record x;
2375
2376 x = link->data.tcp->ack[i];
2377 if (x.active == 1)
2378 {
2379 int seq_diff;
2380
2381 seq_diff = SeqDiff(x.ack_old, seq);
2382 if (seq_diff >= 0)
2383 {
2384 if (seq_diff_min >= 0)
2385 {
2386 if (seq_diff < seq_diff_min)
2387 {
2388 delta = x.delta;
2389 seq_diff_min = seq_diff;
2390 }
2391 }
2392 else
2393 {
2394 delta = x.delta;
2395 seq_diff_min = seq_diff;
2396 }
2397 }
2398 }
2399 }
2400 return (delta);
2401}
2402
2403
2404void
2405AddSeq(struct ip *pip, struct alias_link *link, int delta)
2406{
2407/*
2408When a TCP packet has been altered in length, save this
2409information in a circular list. If enough packets have
2410been altered, then this list will begin to overwrite itself.
2411*/
2412
2413 struct tcphdr *tc;
2414 struct ack_data_record x;
2415 int hlen, tlen, dlen;
2416 int i;
2417
2418 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2419
2420 hlen = (pip->ip_hl + tc->th_off) << 2;
2421 tlen = ntohs(pip->ip_len);
2422 dlen = tlen - hlen;
2423
2424 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2425 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2426 x.delta = delta;
2427 x.active = 1;
2428
2429 i = link->data.tcp->state.index;
2430 link->data.tcp->ack[i] = x;
2431
2432 i++;
2433 if (i == N_LINK_TCP_DATA)
2434 link->data.tcp->state.index = 0;
2435 else
2436 link->data.tcp->state.index = i;
2437}
2438
2439void
2440SetExpire(struct alias_link *link, int expire)
2441{
2442 if (expire == 0)
2443 {
2444 link->flags &= ~LINK_PERMANENT;
2445 DeleteLink(link);
2446 }
2447 else if (expire == -1)
2448 {
2449 link->flags |= LINK_PERMANENT;
2450 }
2451 else if (expire > 0)
2452 {
2453 link->expire_time = expire;
2454 }
2455 else
2456 {
2457#ifdef DEBUG
2458 fprintf(stderr, "PacketAlias/SetExpire(): ");
2459 fprintf(stderr, "error in expire parameter\n");
2460#endif
2461 }
2462}
2463
2464void
2465ClearCheckNewLink(void)
2466{
2467 newDefaultLink = 0;
2468}
2469
7ba0088d
A
2470void
2471SetLastLineCrlfTermed(struct alias_link *link, int yes)
2472{
2473
2474 if (yes)
2475 link->flags |= LINK_LAST_LINE_CRLF_TERMED;
2476 else
2477 link->flags &= ~LINK_LAST_LINE_CRLF_TERMED;
2478}
2479
2480int
2481GetLastLineCrlfTermed(struct alias_link *link)
2482{
2483
2484 return (link->flags & LINK_LAST_LINE_CRLF_TERMED);
2485}
2486
2487void
2488SetDestCallId(struct alias_link *link, u_int16_t cid)
2489{
2490
2491 deleteAllLinks = 1;
2492 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2493 link->src_port, cid, link->alias_port, link->link_type);
2494 deleteAllLinks = 0;
2495}
2496
b7080c8e
A
2497
2498/* Miscellaneous Functions
2499
2500 HouseKeeping()
2501 InitPacketAliasLog()
2502 UninitPacketAliasLog()
2503*/
2504
2505/*
2506 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2507 is called to find and remove timed-out aliasing links. Logic exists
2508 to sweep through the entire table and linked list structure
2509 every 60 seconds.
2510
2511 (prototype in alias_local.h)
2512*/
2513
2514void
2515HouseKeeping(void)
2516{
2517 int i, n, n100;
2518 struct timeval tv;
2519 struct timezone tz;
2520
2521 /*
2522 * Save system time (seconds) in global variable timeStamp for
2523 * use by other functions. This is done so as not to unnecessarily
2524 * waste timeline by making system calls.
2525 */
2526 gettimeofday(&tv, &tz);
2527 timeStamp = tv.tv_sec;
2528
2529 /* Compute number of spokes (output table link chains) to cover */
2530 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2531 n100 *= timeStamp - lastCleanupTime;
2532 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2533
2534 n = n100/100;
2535
2536 /* Handle different cases */
2537 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2538 {
2539 n = ALIAS_CLEANUP_MAX_SPOKES;
2540 lastCleanupTime = timeStamp;
2541 houseKeepingResidual = 0;
2542
2543 for (i=0; i<n; i++)
2544 IncrementalCleanup();
2545 }
2546 else if (n > 0)
2547 {
2548 lastCleanupTime = timeStamp;
2549 houseKeepingResidual = n100 - 100*n;
2550
2551 for (i=0; i<n; i++)
2552 IncrementalCleanup();
2553 }
2554 else if (n < 0)
2555 {
2556#ifdef DEBUG
2557 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2558 fprintf(stderr, "something unexpected in time values\n");
2559#endif
2560 lastCleanupTime = timeStamp;
2561 houseKeepingResidual = 0;
2562 }
2563}
2564
2565
2566/* Init the log file and enable logging */
2567static void
2568InitPacketAliasLog(void)
2569{
2570 if ((~packetAliasMode & PKT_ALIAS_LOG)
2571 && (monitorFile = fopen("/var/log/alias.log", "w")))
2572 {
2573 packetAliasMode |= PKT_ALIAS_LOG;
2574 fprintf(monitorFile,
2575 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2576 }
2577}
2578
2579
2580/* Close the log-file and disable logging. */
2581static void
2582UninitPacketAliasLog(void)
2583{
2584 if (monitorFile) {
2585 fclose(monitorFile);
2586 monitorFile = NULL;
2587 }
2588 packetAliasMode &= ~PKT_ALIAS_LOG;
2589}
2590
2591
2592
2593
2594
2595
2596/* Outside world interfaces
2597
2598-- "outside world" means other than alias*.c routines --
2599
2600 PacketAliasRedirectPort()
7ba0088d
A
2601 PacketAliasAddServer()
2602 PacketAliasRedirectProto()
b7080c8e
A
2603 PacketAliasRedirectAddr()
2604 PacketAliasRedirectDelete()
2605 PacketAliasSetAddress()
2606 PacketAliasInit()
2607 PacketAliasUninit()
2608 PacketAliasSetMode()
2609
2610(prototypes in alias.h)
2611*/
2612
2613/* Redirection from a specific public addr:port to a
7ba0088d 2614 private addr:port */
b7080c8e
A
2615struct alias_link *
2616PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
2617 struct in_addr dst_addr, u_short dst_port,
2618 struct in_addr alias_addr, u_short alias_port,
2619 u_char proto)
2620{
2621 int link_type;
2622 struct alias_link *link;
2623
2624 switch(proto)
2625 {
2626 case IPPROTO_UDP:
2627 link_type = LINK_UDP;
2628 break;
2629 case IPPROTO_TCP:
2630 link_type = LINK_TCP;
2631 break;
2632 default:
2633#ifdef DEBUG
2634 fprintf(stderr, "PacketAliasRedirectPort(): ");
2635 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2636#endif
2637 return NULL;
2638 }
2639
2640 link = AddLink(src_addr, dst_addr, alias_addr,
2641 src_port, dst_port, alias_port,
2642 link_type);
2643
2644 if (link != NULL)
2645 {
2646 link->flags |= LINK_PERMANENT;
2647 }
2648#ifdef DEBUG
2649 else
2650 {
2651 fprintf(stderr, "PacketAliasRedirectPort(): "
2652 "call to AddLink() failed\n");
2653 }
2654#endif
2655
2656 return link;
2657}
2658
7ba0088d 2659/* Add server to the pool of servers */
b7080c8e 2660int
7ba0088d 2661PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
b7080c8e 2662{
7ba0088d
A
2663 struct server *server;
2664
2665 server = malloc(sizeof(struct server));
2666
2667 if (server != NULL) {
2668 struct server *head;
2669
2670 server->addr = addr;
2671 server->port = port;
b7080c8e 2672
7ba0088d
A
2673 head = link->server;
2674 if (head == NULL)
2675 server->next = server;
2676 else {
2677 struct server *s;
b7080c8e 2678
7ba0088d
A
2679 for (s = head; s->next != head; s = s->next);
2680 s->next = server;
2681 server->next = head;
2682 }
2683 link->server = server;
2684 return (0);
2685 } else
2686 return (-1);
b7080c8e
A
2687}
2688
7ba0088d
A
2689/* Redirect packets of a given IP protocol from a specific
2690 public address to a private address */
2691struct alias_link *
2692PacketAliasRedirectProto(struct in_addr src_addr,
2693 struct in_addr dst_addr,
2694 struct in_addr alias_addr,
2695 u_char proto)
b7080c8e 2696{
7ba0088d 2697 struct alias_link *link;
b7080c8e 2698
7ba0088d
A
2699 link = AddLink(src_addr, dst_addr, alias_addr,
2700 NO_SRC_PORT, NO_DEST_PORT, 0,
2701 proto);
2702
2703 if (link != NULL)
2704 {
2705 link->flags |= LINK_PERMANENT;
2706 }
2707#ifdef DEBUG
2708 else
2709 {
2710 fprintf(stderr, "PacketAliasRedirectProto(): "
2711 "call to AddLink() failed\n");
2712 }
2713#endif
2714
2715 return link;
b7080c8e
A
2716}
2717
2718/* Static address translation */
2719struct alias_link *
2720PacketAliasRedirectAddr(struct in_addr src_addr,
2721 struct in_addr alias_addr)
2722{
2723 struct alias_link *link;
2724
2725 link = AddLink(src_addr, nullAddress, alias_addr,
2726 0, 0, 0,
2727 LINK_ADDR);
2728
2729 if (link != NULL)
2730 {
2731 link->flags |= LINK_PERMANENT;
2732 }
2733#ifdef DEBUG
2734 else
2735 {
2736 fprintf(stderr, "PacketAliasRedirectAddr(): "
2737 "call to AddLink() failed\n");
2738 }
2739#endif
2740
2741 return link;
2742}
2743
2744
2745void
2746PacketAliasRedirectDelete(struct alias_link *link)
2747{
2748/* This is a dangerous function to put in the API,
2749 because an invalid pointer can crash the program. */
2750
2751 deleteAllLinks = 1;
2752 DeleteLink(link);
2753 deleteAllLinks = 0;
2754}
2755
2756
2757void
2758PacketAliasSetAddress(struct in_addr addr)
2759{
2760 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2761 && aliasAddress.s_addr != addr.s_addr)
2762 CleanupAliasData();
2763
2764 aliasAddress = addr;
2765}
2766
2767
2768void
2769PacketAliasSetTarget(struct in_addr target_addr)
2770{
2771 targetAddress = target_addr;
2772}
2773
2774
2775void
2776PacketAliasInit(void)
2777{
2778 int i;
2779 struct timeval tv;
2780 struct timezone tz;
2781 static int firstCall = 1;
2782
2783 if (firstCall == 1)
2784 {
2785 gettimeofday(&tv, &tz);
2786 timeStamp = tv.tv_sec;
2787 lastCleanupTime = tv.tv_sec;
2788 houseKeepingResidual = 0;
2789
2790 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
7ba0088d 2791 LIST_INIT(&linkTableOut[i]);
b7080c8e 2792 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
7ba0088d 2793 LIST_INIT(&linkTableIn[i]);
b7080c8e
A
2794
2795 atexit(PacketAliasUninit);
2796 firstCall = 0;
2797 }
2798 else
2799 {
2800 deleteAllLinks = 1;
2801 CleanupAliasData();
2802 deleteAllLinks = 0;
2803 }
2804
7ba0088d
A
2805 aliasAddress.s_addr = INADDR_ANY;
2806 targetAddress.s_addr = INADDR_ANY;
b7080c8e
A
2807
2808 icmpLinkCount = 0;
2809 udpLinkCount = 0;
2810 tcpLinkCount = 0;
7ba0088d
A
2811 pptpLinkCount = 0;
2812 protoLinkCount = 0;
b7080c8e
A
2813 fragmentIdLinkCount = 0;
2814 fragmentPtrLinkCount = 0;
2815 sockCount = 0;
2816
2817 cleanupIndex =0;
2818
2819 packetAliasMode = PKT_ALIAS_SAME_PORTS
2820 | PKT_ALIAS_USE_SOCKETS
2821 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
b7080c8e
A
2822}
2823
2824void
2825PacketAliasUninit(void) {
2826 deleteAllLinks = 1;
2827 CleanupAliasData();
2828 deleteAllLinks = 0;
2829 UninitPacketAliasLog();
2830#ifndef NO_FW_PUNCH
2831 UninitPunchFW();
2832#endif
2833}
2834
2835
2836/* Change mode for some operations */
2837unsigned int
2838PacketAliasSetMode(
2839 unsigned int flags, /* Which state to bring flags to */
2840 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2841 probe for flag values) */
2842)
2843{
2844/* Enable logging? */
2845 if (flags & mask & PKT_ALIAS_LOG)
2846 {
2847 InitPacketAliasLog(); /* Do the enable */
2848 } else
2849/* _Disable_ logging? */
2850 if (~flags & mask & PKT_ALIAS_LOG) {
2851 UninitPacketAliasLog();
2852 }
2853
2854#ifndef NO_FW_PUNCH
2855/* Start punching holes in the firewall? */
2856 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2857 InitPunchFW();
2858 } else
2859/* Stop punching holes in the firewall? */
2860 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2861 UninitPunchFW();
2862 }
2863#endif
2864
2865/* Other flags can be set/cleared without special action */
2866 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2867 return packetAliasMode;
2868}
2869
2870
2871int
2872PacketAliasCheckNewLink(void)
2873{
2874 return newDefaultLink;
2875}
2876
2877
2878#ifndef NO_FW_PUNCH
2879
2880/*****************
2881 Code to support firewall punching. This shouldn't really be in this
2882 file, but making variables global is evil too.
2883 ****************/
2884
2885/* Firewall include files */
b7080c8e
A
2886#include <net/if.h>
2887#include <netinet/ip_fw.h>
2888#include <string.h>
2889#include <err.h>
2890
2891static void ClearAllFWHoles(void);
2892
2893static int fireWallBaseNum; /* The first firewall entry free for our use */
2894static int fireWallNumNums; /* How many entries can we use? */
2895static int fireWallActiveNum; /* Which entry did we last use? */
2896static char *fireWallField; /* bool array for entries */
2897
2898#define fw_setfield(field, num) \
2899do { \
7ba0088d 2900 (field)[(num) - fireWallBaseNum] = 1; \
b7080c8e
A
2901} /*lint -save -e717 */ while(0) /*lint -restore */
2902#define fw_clrfield(field, num) \
2903do { \
7ba0088d 2904 (field)[(num) - fireWallBaseNum] = 0; \
b7080c8e 2905} /*lint -save -e717 */ while(0) /*lint -restore */
7ba0088d 2906#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
b7080c8e
A
2907
2908static void
2909InitPunchFW(void) {
2910 fireWallField = malloc(fireWallNumNums);
2911 if (fireWallField) {
2912 memset(fireWallField, 0, fireWallNumNums);
2913 if (fireWallFD < 0) {
2914 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2915 }
2916 ClearAllFWHoles();
2917 fireWallActiveNum = fireWallBaseNum;
2918 }
2919}
2920
2921static void
2922UninitPunchFW(void) {
2923 ClearAllFWHoles();
2924 if (fireWallFD >= 0)
2925 close(fireWallFD);
2926 fireWallFD = -1;
2927 if (fireWallField)
2928 free(fireWallField);
2929 fireWallField = NULL;
2930 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2931}
2932
2933/* Make a certain link go through the firewall */
2934void
2935PunchFWHole(struct alias_link *link) {
2936 int r; /* Result code */
2937 struct ip_fw rule; /* On-the-fly built rule */
2938 int fwhole; /* Where to punch hole */
2939
2940/* Don't do anything unless we are asked to */
2941 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2942 fireWallFD < 0 ||
7ba0088d 2943 link->link_type != LINK_TCP)
b7080c8e
A
2944 return;
2945
2946 memset(&rule, 0, sizeof rule);
2947
2948/** Build rule **/
2949
2950 /* Find empty slot */
2951 for (fwhole = fireWallActiveNum;
2952 fwhole < fireWallBaseNum + fireWallNumNums &&
2953 fw_tstfield(fireWallField, fwhole);
2954 fwhole++)
2955 ;
7ba0088d 2956 if (fwhole == fireWallBaseNum + fireWallNumNums) {
b7080c8e
A
2957 for (fwhole = fireWallBaseNum;
2958 fwhole < fireWallActiveNum &&
2959 fw_tstfield(fireWallField, fwhole);
2960 fwhole++)
2961 ;
2962 if (fwhole == fireWallActiveNum) {
2963 /* No rule point empty - we can't punch more holes. */
2964 fireWallActiveNum = fireWallBaseNum;
2965#ifdef DEBUG
2966 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2967#endif
2968 return;
2969 }
2970 }
2971 /* Start next search at next position */
2972 fireWallActiveNum = fwhole+1;
2973
2974 /* Build generic part of the two rules */
2975 rule.fw_number = fwhole;
7ba0088d
A
2976 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
2977 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */
2978 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
b7080c8e
A
2979 rule.fw_prot = IPPROTO_TCP;
2980 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2981 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2982
2983 /* Build and apply specific part of the rules */
2984 rule.fw_src = GetOriginalAddress(link);
2985 rule.fw_dst = GetDestAddress(link);
2986 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2987 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2988
2989 /* Skip non-bound links - XXX should not be strictly necessary,
2990 but seems to leave hole if not done. Leak of non-bound links?
2991 (Code should be left even if the problem is fixed - it is a
2992 clear optimization) */
2993 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2994 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2995#ifdef DEBUG
2996 if (r)
2997 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2998#endif
2999 rule.fw_src = GetDestAddress(link);
3000 rule.fw_dst = GetOriginalAddress(link);
3001 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
3002 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
3003 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
3004#ifdef DEBUG
3005 if (r)
3006 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
3007#endif
3008 }
3009/* Indicate hole applied */
3010 link->data.tcp->fwhole = fwhole;
3011 fw_setfield(fireWallField, fwhole);
3012}
3013
3014/* Remove a hole in a firewall associated with a particular alias
3015 link. Calling this too often is harmless. */
3016static void
3017ClearFWHole(struct alias_link *link) {
7ba0088d 3018 if (link->link_type == LINK_TCP) {
b7080c8e
A
3019 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
3020 struct ip_fw rule;
3021
3022 if (fwhole < 0)
3023 return;
3024
3025 memset(&rule, 0, sizeof rule);
3026 rule.fw_number = fwhole;
3027 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
3028 ;
3029 fw_clrfield(fireWallField, fwhole);
3030 link->data.tcp->fwhole = -1;
3031 }
3032}
3033
3034/* Clear out the entire range dedicated to firewall holes. */
3035static void
3036ClearAllFWHoles(void) {
3037 struct ip_fw rule; /* On-the-fly built rule */
3038 int i;
3039
3040 if (fireWallFD < 0)
3041 return;
3042
3043 memset(&rule, 0, sizeof rule);
3044 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
3045 rule.fw_number = i;
3046 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
3047 ;
3048 }
3049 memset(fireWallField, 0, fireWallNumNums);
3050}
3051#endif
7ba0088d
A
3052
3053void
3054PacketAliasSetFWBase(unsigned int base, unsigned int num) {
3055#ifndef NO_FW_PUNCH
3056 fireWallBaseNum = base;
3057 fireWallNumNums = num;
3058#endif
3059}
f47db663
A
3060
3061void
3062DumpInfo(void)
3063{
3064 int i, icount = 0;
3065 struct alias_link *link;
3066
3067 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
3068 {
3069 link = LIST_FIRST(&linkTableOut[i]);
3070 while (link != NULL)
3071 {
3072 struct alias_link *link_next;
3073 char src_str[32], dst_str[32], alias_str[32];
3074
3075 snprintf(src_str, sizeof(src_str), "%s:%u",
3076 inet_ntoa(link->src_addr), ntohs(link->src_port));
3077 snprintf(dst_str, sizeof(dst_str), "%s:%u",
3078 inet_ntoa(link->dst_addr), ntohs(link->dst_port));
3079 snprintf(alias_str, sizeof(alias_str), "%s:%u",
3080 inet_ntoa(link->alias_addr), ntohs(link->alias_port));
3081
3082 syslog(LOG_ERR, " linkTableOut[%d:%d] src= %s dst= %s alias= %s flags= 0x%x linktype= %d ts= %d exp= %d fd= %d",
3083 i, icount, src_str, dst_str, alias_str,
3084 link->flags, link->link_type, link->timestamp, link->expire_time, link->sockfd);
3085
3086 link_next = LIST_NEXT(link, list_out);
3087 icount++;
3088 link = link_next;
3089 }
3090 }
3091
3092}