1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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 #ifdef _KERNEL
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/lock.h>
35 #include <sys/module.h>
36 #include <sys/mutex.h>
37 #include <sys/rwlock.h>
38 #include <sys/stdarg.h>
39 #include <sys/syslog.h>
40 #else
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <sys/errno.h>
45 #include <sys/time.h>
46 #include <unistd.h>
47 #endif
48
49 #include <sys/socket.h>
50 #include <netinet/tcp.h>
51
52 #ifdef _KERNEL
53 #include <netinet/libalias/alias.h>
54 #include <netinet/libalias/alias_local.h>
55 #include <netinet/libalias/alias_mod.h>
56 #include <net/if.h>
57 #else
58 #include "alias.h"
59 #include "alias_local.h"
60 #include "alias_mod.h"
61 #endif
62
63 #include "alias_db.h"
64
65 #ifdef _KERNEL
66 static struct mtx list_mtx;
67 MTX_SYSINIT(libalias_list, &list_mtx, "libalias list lock", MTX_DEF);
68 #endif
69 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
70 int LibAliasTime;
71
72 /* Kernel module definition. */
73 #ifdef _KERNEL
74 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
75
76 MODULE_VERSION(libalias, 1);
77
78 static int
alias_mod_handler(module_t mod,int type,void * data)79 alias_mod_handler(module_t mod, int type, void *data)
80 {
81 switch (type) {
82 case MOD_QUIESCE:
83 case MOD_UNLOAD:
84 finishoff();
85 case MOD_LOAD:
86 return (0);
87 default:
88 return (EINVAL);
89 }
90 }
91
92 static moduledata_t alias_mod = {
93 "alias", alias_mod_handler, NULL
94 };
95
96 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
97 #endif
98
99 SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
100 SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
101 SPLAY_GENERATE(splay_internal_endpoint, alias_link, all.internal_endpoint,
102 cmp_internal_endpoint);
103
104 /*
105 * Fully specified links of a group, ordered by the remote endpoint
106 * (dst_addr, dst_port). Links that share an endpoint (for example a
107 * permanent redirect that overrides an older one) are ordered newest
108 * first, which keeps the "most recent link wins" behaviour of the former
109 * list. A lookup needle has la == NULL and sorts before every real link
110 * with the same endpoint, so RB_NFIND() returns the newest one.
111 */
112 static inline int
cmp_full(struct alias_link * a,struct alias_link * b)113 cmp_full(struct alias_link *a, struct alias_link *b)
114 {
115 if (a->dst_addr.s_addr != b->dst_addr.s_addr)
116 return (a->dst_addr.s_addr > b->dst_addr.s_addr ? 1 : -1);
117 if (a->dst_port != b->dst_port)
118 return (a->dst_port > b->dst_port ? 1 : -1);
119 if (a == b)
120 return (0);
121 if (a->la == NULL)
122 return (-1);
123 if (b->la == NULL)
124 return (1);
125 return (a->seq > b->seq ? -1 : 1);
126 }
127 RB_GENERATE_STATIC(full_in, alias_link, all.in_full, cmp_full);
128
129 static struct group_in *
StartPointIn(struct libalias * la,struct in_addr alias_addr,u_short alias_port,int link_type,int create)130 StartPointIn(struct libalias *la,
131 struct in_addr alias_addr, u_short alias_port, int link_type,
132 int create)
133 {
134 struct group_in *grp;
135 struct group_in needle = {
136 .alias_addr = alias_addr,
137 .alias_port = alias_port,
138 .link_type = link_type
139 };
140
141 grp = SPLAY_FIND(splay_in, &la->linkSplayIn, &needle);
142 if (grp != NULL || !create || (grp = malloc(sizeof(*grp))) == NULL)
143 return (grp);
144 grp->alias_addr = alias_addr;
145 grp->alias_port = alias_port;
146 grp->link_type = link_type;
147 RB_INIT(&grp->full);
148 LIST_INIT(&grp->partial);
149 SPLAY_INSERT(splay_in, &la->linkSplayIn, grp);
150 return (grp);
151 }
152
153 /*
154 * First fully specified link of grp at or after (dst_addr, dst_port),
155 * or NULL. Callers check which fields actually match.
156 */
157 static inline struct alias_link *
FullInNFind(struct group_in * grp,struct in_addr dst_addr,u_short dst_port)158 FullInNFind(struct group_in *grp, struct in_addr dst_addr, u_short dst_port)
159 {
160 struct alias_link needle = {
161 .la = NULL,
162 .dst_addr = dst_addr,
163 .dst_port = dst_port
164 };
165
166 return (RB_NFIND(full_in, &grp->full, &needle));
167 }
168
169 /*
170 * Fully specified link of grp for exactly (dst_addr, dst_port), or NULL.
171 * With several links for the same endpoint, the newest one is returned.
172 */
173 static inline struct alias_link *
FullInFind(struct group_in * grp,struct in_addr dst_addr,u_short dst_port)174 FullInFind(struct group_in *grp, struct in_addr dst_addr, u_short dst_port)
175 {
176 struct alias_link *lnk;
177
178 lnk = FullInNFind(grp, dst_addr, dst_port);
179 if (lnk != NULL &&
180 lnk->dst_addr.s_addr == dst_addr.s_addr &&
181 lnk->dst_port == dst_port)
182 return (lnk);
183 return (NULL);
184 }
185
186 static int
SeqDiff(u_long x,u_long y)187 SeqDiff(u_long x, u_long y)
188 {
189 /* Return the difference between two TCP sequence numbers
190 * This function is encapsulated in case there are any unusual
191 * arithmetic conditions that need to be considered.
192 */
193 return (ntohl(y) - ntohl(x));
194 }
195
196 #ifdef _KERNEL
197 static void
AliasLog(char * str,const char * format,...)198 AliasLog(char *str, const char *format, ...)
199 {
200 va_list ap;
201
202 va_start(ap, format);
203 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
204 va_end(ap);
205 }
206 #else
207 static void
AliasLog(FILE * stream,const char * format,...)208 AliasLog(FILE *stream, const char *format, ...)
209 {
210 va_list ap;
211
212 va_start(ap, format);
213 vfprintf(stream, format, ap);
214 va_end(ap);
215 fflush(stream);
216 }
217 #endif
218
219 static void
ShowAliasStats(struct libalias * la)220 ShowAliasStats(struct libalias *la)
221 {
222 LIBALIAS_LOCK_ASSERT(la);
223 /* Used for debugging */
224 if (la->logDesc) {
225 int tot = la->icmpLinkCount + la->udpLinkCount +
226 (la->sctpLinkCount>>1) + /* sctp counts half associations */
227 la->tcpLinkCount + la->pptpLinkCount +
228 la->protoLinkCount + la->fragmentIdLinkCount +
229 la->fragmentPtrLinkCount;
230
231 AliasLog(la->logDesc,
232 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
233 la->icmpLinkCount,
234 la->udpLinkCount,
235 la->tcpLinkCount,
236 la->sctpLinkCount>>1, /* sctp counts half associations */
237 la->pptpLinkCount,
238 la->protoLinkCount,
239 la->fragmentIdLinkCount,
240 la->fragmentPtrLinkCount,
241 tot);
242 #ifndef _KERNEL
243 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
244 #endif
245 }
246 }
247
SctpShowAliasStats(struct libalias * la)248 void SctpShowAliasStats(struct libalias *la)
249 {
250 ShowAliasStats(la);
251 }
252
253 /* get random port in network byte order */
254 static u_short
_RandomPort(struct libalias * la)255 _RandomPort(struct libalias *la) {
256 u_short port;
257
258 port = la->aliasPortLower +
259 arc4random_uniform(la->aliasPortLength);
260
261 return htons(port);
262 }
263
264 /* GetNewPort() allocates port numbers. Note that if a port number
265 is already in use, that does not mean that it cannot be used by
266 another link concurrently. This is because GetNewPort() looks for
267 unused triplets: (dest addr, dest port, alias port). */
268
269 static int
GetNewPort(struct libalias * la,struct alias_link * lnk,int alias_port_param)270 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
271 {
272 int i;
273 int max_trials;
274 u_short port;
275
276 LIBALIAS_LOCK_ASSERT(la);
277 /*
278 * Description of alias_port_param for GetNewPort(). When
279 * this parameter is zero or positive, it precisely specifies
280 * the port number. GetNewPort() will return this number
281 * without check that it is in use.
282 *
283 * The aliasing port is automatically selected by one of
284 * two methods below:
285 *
286 * When this parameter is GET_ALIAS_PORT, it indicates to get
287 * a randomly selected port number.
288 */
289 if (alias_port_param >= 0 && alias_port_param < 0x10000) {
290 lnk->alias_port = (u_short) alias_port_param;
291 return (0);
292 }
293 if (alias_port_param != GET_ALIAS_PORT) {
294 #ifdef LIBALIAS_DEBUG
295 fprintf(stderr, "PacketAlias/GetNewPort(): ");
296 fprintf(stderr, "input parameter error\n");
297 #endif
298 return (-1);
299 }
300
301 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
302
303 if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
304 lnk->link_type == LINK_UDP) {
305 /* Try reuse the same alias address:port for all destinations
306 * from the same internal address:port, as per RFC 4787.
307 */
308 struct alias_link *search_result = FindLinkByInternalEndpoint(
309 la, lnk->src_addr, lnk->src_port, lnk->link_type);
310 if (search_result != NULL) {
311 lnk->alias_port = search_result->alias_port;
312 return (0);
313 }
314 }
315
316 /*
317 * When the PKT_ALIAS_SAME_PORTS option is chosen,
318 * the first try will be the actual source port. If
319 * this is already in use, the remainder of the
320 * trials will be random.
321 */
322 port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
323 ? lnk->src_port
324 : _RandomPort(la);
325
326 /* Port number search */
327 for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
328 struct group_in *grp;
329 struct alias_link *search_result;
330
331 grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0);
332 if (grp == NULL)
333 break;
334
335 /* As per RFC 4787, UDP cannot share the same alias port among
336 * multiple internal endpoints
337 */
338 if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
339 lnk->link_type == LINK_UDP)
340 continue;
341
342 search_result = FullInFind(grp, lnk->dst_addr, lnk->dst_port);
343 if (search_result == NULL)
344 break; /* port is free */
345 }
346
347 if (i >= max_trials) {
348 #ifdef LIBALIAS_DEBUG
349 fprintf(stderr, "PacketAlias/GetNewPort(): ");
350 fprintf(stderr, "could not find free port\n");
351 #endif
352 return (-1);
353 }
354
355 #ifndef NO_USE_SOCKETS
356 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) &&
357 (lnk->flags & LINK_PARTIALLY_SPECIFIED) &&
358 ((lnk->link_type == LINK_TCP) ||
359 (lnk->link_type == LINK_UDP))) {
360 if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) {
361 return (-1);
362 }
363 }
364 #endif
365 lnk->alias_port = port;
366
367 return (0);
368 }
369
370 #ifndef NO_USE_SOCKETS
371 static u_short
GetSocket(struct libalias * la,u_short port_net,int * sockfd,int link_type)372 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
373 {
374 int err;
375 int sock;
376 struct sockaddr_in sock_addr;
377
378 LIBALIAS_LOCK_ASSERT(la);
379 if (link_type == LINK_TCP)
380 sock = socket(AF_INET, SOCK_STREAM, 0);
381 else if (link_type == LINK_UDP)
382 sock = socket(AF_INET, SOCK_DGRAM, 0);
383 else {
384 #ifdef LIBALIAS_DEBUG
385 fprintf(stderr, "PacketAlias/GetSocket(): ");
386 fprintf(stderr, "incorrect link type\n");
387 #endif
388 return (0);
389 }
390
391 if (sock < 0) {
392 #ifdef LIBALIAS_DEBUG
393 fprintf(stderr, "PacketAlias/GetSocket(): ");
394 fprintf(stderr, "socket() error %d\n", *sockfd);
395 #endif
396 return (0);
397 }
398 sock_addr.sin_family = AF_INET;
399 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
400 sock_addr.sin_port = port_net;
401
402 err = bind(sock,
403 (struct sockaddr *)&sock_addr,
404 sizeof(sock_addr));
405 if (err == 0) {
406 la->sockCount++;
407 *sockfd = sock;
408 return (1);
409 } else {
410 close(sock);
411 return (0);
412 }
413 }
414 #endif
415
416 /* FindNewPortGroup() returns a base port number for an available
417 range of contiguous port numbers. Note that if a port number
418 is already in use, that does not mean that it cannot be used by
419 another link concurrently. This is because FindNewPortGroup()
420 looks for unused triplets: (dest addr, dest port, alias port). */
421
422 int
FindNewPortGroup(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short src_port,u_short dst_port,u_short port_count,u_char proto,u_char align)423 FindNewPortGroup(struct libalias *la,
424 struct in_addr dst_addr,
425 struct in_addr alias_addr,
426 u_short src_port,
427 u_short dst_port,
428 u_short port_count,
429 u_char proto,
430 u_char align)
431 {
432 int i, j;
433 int max_trials;
434 u_short port;
435 int link_type;
436
437 LIBALIAS_LOCK_ASSERT(la);
438 /*
439 * Get link_type from protocol
440 */
441
442 switch (proto) {
443 case IPPROTO_UDP:
444 link_type = LINK_UDP;
445 break;
446 case IPPROTO_TCP:
447 link_type = LINK_TCP;
448 break;
449 default:
450 return (0);
451 break;
452 }
453
454 /*
455 * The aliasing port is automatically selected by one of two
456 * methods below:
457 */
458 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
459
460 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
461 /*
462 * When the ALIAS_SAME_PORTS option is chosen, the first
463 * try will be the actual source port. If this is already
464 * in use, the remainder of the trials will be random.
465 */
466 port = src_port;
467
468 } else {
469 port = _RandomPort(la);
470 }
471
472 /* Port number search */
473 for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
474 struct alias_link *search_result;
475
476 if (align)
477 port &= htons(0xfffe);
478
479 for (j = 0; j < port_count; j++) {
480 u_short port_j = ntohs(port) + j;
481
482 if ((search_result = FindLinkIn(la, dst_addr,
483 alias_addr, dst_port, htons(port_j),
484 link_type, 0)) != NULL)
485 break;
486 }
487
488 /* Found a good range, return base */
489 if (j == port_count)
490 return (port);
491 }
492
493 #ifdef LIBALIAS_DEBUG
494 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
495 fprintf(stderr, "could not find free port(s)\n");
496 #endif
497
498 return (0);
499 }
500
501 static void
CleanupAliasData(struct libalias * la,int deletePermanent)502 CleanupAliasData(struct libalias *la, int deletePermanent)
503 {
504 struct alias_link *lnk, *lnk_tmp;
505
506 LIBALIAS_LOCK_ASSERT(la);
507
508 /* permanent entries may stay */
509 TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp)
510 DeleteLink(&lnk, deletePermanent);
511 }
512 static void
CleanupLink(struct libalias * la,struct alias_link ** lnk,int deletePermanent)513 CleanupLink(struct libalias *la, struct alias_link **lnk, int deletePermanent)
514 {
515 LIBALIAS_LOCK_ASSERT(la);
516
517 if (lnk == NULL || *lnk == NULL)
518 return;
519
520 if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.time) {
521 DeleteLink(lnk, deletePermanent);
522 if ((*lnk) == NULL)
523 return;
524 }
525
526 /* move to end, swap may fail on a single entry list */
527 TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list);
528 TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list);
529 }
530
531 static struct alias_link *
UseLink(struct libalias * la,struct alias_link * lnk)532 UseLink(struct libalias *la, struct alias_link *lnk)
533 {
534 CleanupLink(la, &lnk, 0);
535 if (lnk != NULL)
536 lnk->timestamp = LibAliasTime;
537 return (lnk);
538 }
539
540 static void
DeleteLink(struct alias_link ** plnk,int deletePermanent)541 DeleteLink(struct alias_link **plnk, int deletePermanent)
542 {
543 struct alias_link *lnk = *plnk;
544 struct libalias *la = lnk->la;
545
546 LIBALIAS_LOCK_ASSERT(la);
547 /* Don't do anything if the link is marked permanent */
548 if (!deletePermanent && (lnk->flags & LINK_PERMANENT))
549 return;
550
551 #ifndef NO_FW_PUNCH
552 /* Delete associated firewall hole, if any */
553 ClearFWHole(lnk);
554 #endif
555
556 switch (lnk->link_type) {
557 case LINK_PPTP:
558 LIST_REMOVE(lnk, pptp.list);
559 break;
560 default: {
561 struct group_in *grp;
562
563 /* Free memory allocated for LSNAT server pool */
564 if (lnk->server != NULL) {
565 struct server *head, *curr, *next;
566
567 head = curr = lnk->server;
568 do {
569 next = curr->next;
570 free(curr);
571 } while ((curr = next) != head);
572 } else {
573 /* Adjust output table pointers */
574 SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
575 }
576
577 /*
578 * Adjust input table pointers. AddLink() put every
579 * non-PPTP link in its group, and the group is freed only
580 * when it is empty, so the group must exist here.
581 */
582 grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port,
583 lnk->link_type, 0);
584 #ifdef _KERNEL
585 KASSERT(grp != NULL, ("%s: link %p has no group",
586 __func__, lnk));
587 #endif
588 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
589 LIST_REMOVE(lnk, all.in);
590 else
591 RB_REMOVE(full_in, &grp->full, lnk);
592
593 /* Remove intermediate node, if empty */
594 if (RB_EMPTY(&grp->full) && LIST_EMPTY(&grp->partial)) {
595 SPLAY_REMOVE(splay_in, &la->linkSplayIn, grp);
596 free(grp);
597 }
598
599 /* Adjust "internal endpoint" table pointer */
600 SPLAY_REMOVE(splay_internal_endpoint,
601 &la->linkSplayInternalEndpoint, lnk);
602 }
603 break;
604 }
605
606 /* remove from housekeeping */
607 TAILQ_REMOVE(&la->checkExpire, lnk, expire.list);
608
609 #ifndef NO_USE_SOCKETS
610 /* Close socket, if one has been allocated */
611 if (lnk->sockfd != -1) {
612 la->sockCount--;
613 close(lnk->sockfd);
614 }
615 #endif
616 /* Link-type dependent cleanup */
617 switch (lnk->link_type) {
618 case LINK_ICMP:
619 la->icmpLinkCount--;
620 break;
621 case LINK_UDP:
622 la->udpLinkCount--;
623 break;
624 case LINK_TCP:
625 la->tcpLinkCount--;
626 free(lnk->data.tcp);
627 break;
628 case LINK_PPTP:
629 la->pptpLinkCount--;
630 break;
631 case LINK_FRAGMENT_ID:
632 la->fragmentIdLinkCount--;
633 break;
634 case LINK_FRAGMENT_PTR:
635 la->fragmentPtrLinkCount--;
636 if (lnk->data.frag_ptr != NULL)
637 free(lnk->data.frag_ptr);
638 break;
639 case LINK_ADDR:
640 break;
641 default:
642 la->protoLinkCount--;
643 break;
644 }
645
646 /* Free memory */
647 free(lnk);
648 *plnk = NULL;
649
650 /* Write statistics, if logging enabled */
651 if (la->packetAliasMode & PKT_ALIAS_LOG) {
652 ShowAliasStats(la);
653 }
654 }
655
656 struct alias_link *
AddLink(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,struct in_addr alias_addr,u_short src_port,u_short dst_port,int alias_port_param,int link_type)657 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
658 struct in_addr alias_addr, u_short src_port, u_short dst_port,
659 int alias_port_param, int link_type)
660 {
661 struct alias_link *lnk;
662
663 LIBALIAS_LOCK_ASSERT(la);
664
665 lnk = malloc(sizeof(struct alias_link));
666 if (lnk == NULL) {
667 #ifdef LIBALIAS_DEBUG
668 fprintf(stderr, "PacketAlias/AddLink(): ");
669 fprintf(stderr, "malloc() call failed.\n");
670 #endif
671 return (NULL);
672 }
673 /* Basic initialization */
674 lnk->la = la;
675 lnk->src_addr = src_addr;
676 lnk->dst_addr = dst_addr;
677 lnk->alias_addr = alias_addr;
678 lnk->proxy_addr.s_addr = INADDR_ANY;
679 lnk->src_port = src_port;
680 lnk->dst_port = dst_port;
681 lnk->proxy_port = 0;
682 lnk->server = NULL;
683 lnk->link_type = link_type;
684 #ifndef NO_USE_SOCKETS
685 lnk->sockfd = -1;
686 #endif
687 lnk->flags = 0;
688 lnk->pflags = 0;
689 lnk->timestamp = LibAliasTime;
690 lnk->seq = la->linkSeq++;
691
692 /* Expiration time */
693 switch (link_type) {
694 case LINK_ICMP:
695 lnk->expire.time = ICMP_EXPIRE_TIME;
696 break;
697 case LINK_UDP:
698 lnk->expire.time = UDP_EXPIRE_TIME;
699 break;
700 case LINK_TCP:
701 lnk->expire.time = TCP_EXPIRE_INITIAL;
702 break;
703 case LINK_FRAGMENT_ID:
704 lnk->expire.time = FRAGMENT_ID_EXPIRE_TIME;
705 break;
706 case LINK_FRAGMENT_PTR:
707 lnk->expire.time = FRAGMENT_PTR_EXPIRE_TIME;
708 break;
709 default:
710 lnk->expire.time = PROTO_EXPIRE_TIME;
711 break;
712 }
713
714 /* Determine alias flags */
715 if (dst_addr.s_addr == INADDR_ANY)
716 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
717 if (dst_port == 0)
718 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
719
720 /* Determine alias port */
721 if (GetNewPort(la, lnk, alias_port_param) != 0) {
722 free(lnk);
723 return (NULL);
724 }
725 /* Link-type dependent initialization */
726 switch (link_type) {
727 case LINK_ICMP:
728 la->icmpLinkCount++;
729 break;
730 case LINK_UDP:
731 la->udpLinkCount++;
732 break;
733 case LINK_TCP: {
734 struct tcp_dat *aux_tcp;
735 int i;
736
737 aux_tcp = malloc(sizeof(struct tcp_dat));
738 if (aux_tcp == NULL) {
739 #ifdef LIBALIAS_DEBUG
740 fprintf(stderr, "PacketAlias/AddLink: ");
741 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
742 #endif
743 free(lnk);
744 return (NULL);
745 }
746
747 la->tcpLinkCount++;
748 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
749 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
750 aux_tcp->state.index = 0;
751 aux_tcp->state.ack_modified = 0;
752 for (i = 0; i < N_LINK_TCP_DATA; i++)
753 aux_tcp->ack[i].active = 0;
754 aux_tcp->fwhole = -1;
755 lnk->data.tcp = aux_tcp;
756 }
757 break;
758 case LINK_PPTP:
759 la->pptpLinkCount++;
760 break;
761 case LINK_FRAGMENT_ID:
762 la->fragmentIdLinkCount++;
763 break;
764 case LINK_FRAGMENT_PTR:
765 la->fragmentPtrLinkCount++;
766 break;
767 case LINK_ADDR:
768 break;
769 default:
770 la->protoLinkCount++;
771 break;
772 }
773
774 switch (link_type) {
775 case LINK_PPTP:
776 LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
777 break;
778 default: {
779 struct group_in *grp;
780
781 grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
782 if (grp == NULL) {
783 free(lnk);
784 return (NULL);
785 }
786
787 /* Set up pointers for output lookup table */
788 SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
789
790 /* Set up pointers for input lookup table */
791 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
792 LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
793 else
794 RB_INSERT(full_in, &grp->full, lnk);
795
796 /* Set up pointers for "internal endpoint" lookup table */
797 SPLAY_INSERT(splay_internal_endpoint,
798 &la->linkSplayInternalEndpoint, lnk);
799 }
800 break;
801 }
802
803 /* Include the element into the housekeeping list */
804 TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
805
806 if (la->packetAliasMode & PKT_ALIAS_LOG)
807 ShowAliasStats(la);
808
809 return (lnk);
810 }
811
812 /*
813 * If alias_port_param is less than zero, alias port will be automatically
814 * chosen. If greater than zero, equal to alias port
815 */
816 static struct alias_link *
ReLink(struct alias_link * old_lnk,struct in_addr src_addr,struct in_addr dst_addr,struct in_addr alias_addr,u_short src_port,u_short dst_port,int alias_port_param,int link_type,int deletePermanent)817 ReLink(struct alias_link *old_lnk,
818 struct in_addr src_addr,
819 struct in_addr dst_addr,
820 struct in_addr alias_addr,
821 u_short src_port,
822 u_short dst_port,
823 int alias_port_param,
824 int link_type,
825 int deletePermanent)
826 {
827 struct alias_link *new_lnk;
828 struct libalias *la = old_lnk->la;
829
830 LIBALIAS_LOCK_ASSERT(la);
831 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
832 src_port, dst_port, alias_port_param,
833 link_type);
834 #ifndef NO_FW_PUNCH
835 if (new_lnk != NULL &&
836 old_lnk->link_type == LINK_TCP &&
837 old_lnk->data.tcp->fwhole > 0) {
838 PunchFWHole(new_lnk);
839 }
840 #endif
841 DeleteLink(&old_lnk, deletePermanent);
842 return (new_lnk);
843 }
844
845 static struct alias_link *
_SearchLinkOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short src_port,u_short dst_port,int link_type)846 _SearchLinkOut(struct libalias *la, struct in_addr src_addr,
847 struct in_addr dst_addr,
848 u_short src_port,
849 u_short dst_port,
850 int link_type) {
851 struct alias_link *lnk;
852 struct alias_link needle = {
853 .src_addr = src_addr,
854 .dst_addr = dst_addr,
855 .src_port = src_port,
856 .dst_port = dst_port,
857 .link_type = link_type
858 };
859
860 lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
861 return (UseLink(la, lnk));
862 }
863
864 static struct alias_link *
_FindLinkOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short src_port,u_short dst_port,int link_type,int replace_partial_links)865 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
866 struct in_addr dst_addr,
867 u_short src_port,
868 u_short dst_port,
869 int link_type,
870 int replace_partial_links)
871 {
872 struct alias_link *lnk;
873
874 LIBALIAS_LOCK_ASSERT(la);
875 lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
876 if (lnk != NULL || !replace_partial_links)
877 return (lnk);
878
879 /* Search for partially specified links. */
880 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
881 lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
882 link_type);
883 if (lnk == NULL)
884 lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
885 dst_port, link_type);
886 }
887 if (lnk == NULL &&
888 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
889 lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
890 link_type);
891 }
892 if (lnk != NULL) {
893 lnk = ReLink(lnk,
894 src_addr, dst_addr, lnk->alias_addr,
895 src_port, dst_port, lnk->alias_port,
896 link_type, 0);
897 }
898 return (lnk);
899 }
900
901 static struct alias_link *
FindLinkOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short src_port,u_short dst_port,int link_type,int replace_partial_links)902 FindLinkOut(struct libalias *la, struct in_addr src_addr,
903 struct in_addr dst_addr,
904 u_short src_port,
905 u_short dst_port,
906 int link_type,
907 int replace_partial_links)
908 {
909 struct alias_link *lnk;
910
911 LIBALIAS_LOCK_ASSERT(la);
912 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
913 link_type, replace_partial_links);
914
915 if (lnk == NULL) {
916 /*
917 * The following allows permanent links to be specified as
918 * using the default source address (i.e. device interface
919 * address) without knowing in advance what that address
920 * is.
921 */
922 if (la->aliasAddress.s_addr != INADDR_ANY &&
923 src_addr.s_addr == la->aliasAddress.s_addr) {
924 lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
925 link_type, replace_partial_links);
926 }
927 }
928 return (lnk);
929 }
930
931 static struct alias_link *
_FindLinkIn(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short dst_port,u_short alias_port,int link_type,int replace_partial_links)932 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
933 struct in_addr alias_addr,
934 u_short dst_port,
935 u_short alias_port,
936 int link_type,
937 int replace_partial_links)
938 {
939 int flags_in;
940 struct group_in *grp;
941 struct alias_link *lnk;
942 struct alias_link *lnk_unknown_all;
943 struct alias_link *lnk_unknown_dst_addr;
944 struct alias_link *lnk_unknown_dst_port;
945 struct in_addr src_addr;
946 u_short src_port;
947
948 LIBALIAS_LOCK_ASSERT(la);
949 /* Initialize pointers */
950 lnk_unknown_all = NULL;
951 lnk_unknown_dst_addr = NULL;
952 lnk_unknown_dst_port = NULL;
953
954 /* If either the dest addr or port is unknown, the search
955 * loop will have to know about this. */
956 flags_in = 0;
957 if (dst_addr.s_addr == INADDR_ANY)
958 flags_in |= LINK_UNKNOWN_DEST_ADDR;
959 if (dst_port == 0)
960 flags_in |= LINK_UNKNOWN_DEST_PORT;
961
962 /* Search loop */
963 grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
964 if (grp == NULL)
965 return (NULL);
966
967 switch (flags_in) {
968 case 0:
969 lnk = FullInFind(grp, dst_addr, dst_port);
970 if (lnk != NULL) {
971 struct alias_link *found;
972
973 found = UseLink(la, lnk);
974 if (found != NULL)
975 return (found);
976 /* link expired */
977 grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
978 if (grp == NULL)
979 return (NULL);
980 }
981 break;
982 case LINK_UNKNOWN_DEST_PORT:
983 /* full links always have dst_port != 0 */
984 lnk = FullInNFind(grp, dst_addr, 0);
985 if (lnk != NULL && lnk->dst_addr.s_addr == dst_addr.s_addr)
986 lnk_unknown_dst_port = lnk;
987 break;
988 case LINK_UNKNOWN_DEST_ADDR:
989 /* the tree is ordered by address first: still a linear scan */
990 RB_FOREACH(lnk, full_in, &grp->full) {
991 if (lnk->dst_port == dst_port) {
992 lnk_unknown_dst_addr = lnk;
993 break;
994 }
995 }
996 break;
997 case LINK_PARTIALLY_SPECIFIED:
998 lnk_unknown_all = RB_MIN(full_in, &grp->full);
999 break;
1000 }
1001
1002 if (lnk_unknown_dst_port == NULL) {
1003 LIST_FOREACH(lnk, &grp->partial, all.in) {
1004 int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
1005
1006 if (flags == LINK_PARTIALLY_SPECIFIED &&
1007 lnk_unknown_all == NULL)
1008 lnk_unknown_all = lnk;
1009 if (flags == LINK_UNKNOWN_DEST_ADDR &&
1010 lnk->dst_port == dst_port &&
1011 lnk_unknown_dst_addr == NULL)
1012 lnk_unknown_dst_addr = lnk;
1013 if (flags == LINK_UNKNOWN_DEST_PORT &&
1014 lnk->dst_addr.s_addr == dst_addr.s_addr) {
1015 lnk_unknown_dst_port = lnk;
1016 break;
1017 }
1018 }
1019 }
1020
1021 lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
1022 : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
1023 : lnk_unknown_all;
1024
1025 if (lnk == NULL || !replace_partial_links)
1026 return (lnk);
1027
1028 if (lnk->server != NULL) { /* LSNAT link */
1029 src_addr = lnk->server->addr;
1030 src_port = lnk->server->port;
1031 lnk->server = lnk->server->next;
1032 } else {
1033 src_addr = lnk->src_addr;
1034 src_port = lnk->src_port;
1035 }
1036
1037 if (link_type == LINK_SCTP) {
1038 lnk->src_addr = src_addr;
1039 lnk->src_port = src_port;
1040 } else {
1041 lnk = ReLink(lnk,
1042 src_addr, dst_addr, alias_addr,
1043 src_port, dst_port, alias_port,
1044 link_type, 0);
1045 }
1046 return (lnk);
1047 }
1048
1049 static struct alias_link *
FindLinkIn(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short dst_port,u_short alias_port,int link_type,int replace_partial_links)1050 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1051 struct in_addr alias_addr,
1052 u_short dst_port,
1053 u_short alias_port,
1054 int link_type,
1055 int replace_partial_links)
1056 {
1057 struct alias_link *lnk;
1058
1059 LIBALIAS_LOCK_ASSERT(la);
1060 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1061 link_type, replace_partial_links);
1062
1063 if (lnk == NULL &&
1064 (la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
1065 link_type == LINK_UDP &&
1066 !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1067 lnk = _FindLinkIn(la, ANY_ADDR, alias_addr, 0, alias_port,
1068 link_type, replace_partial_links);
1069 }
1070
1071 if (lnk == NULL) {
1072 /*
1073 * The following allows permanent links to be specified as
1074 * using the default aliasing address (i.e. device
1075 * interface address) without knowing in advance what that
1076 * address is.
1077 */
1078 if (la->aliasAddress.s_addr != INADDR_ANY &&
1079 alias_addr.s_addr == la->aliasAddress.s_addr) {
1080 lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
1081 link_type, replace_partial_links);
1082 }
1083 }
1084 return (lnk);
1085 }
1086
1087 static struct alias_link *
FindLinkByInternalEndpoint(struct libalias * la,struct in_addr src_addr,u_short src_port,int link_type)1088 FindLinkByInternalEndpoint(struct libalias *la, struct in_addr src_addr,
1089 u_short src_port,
1090 int link_type)
1091 {
1092 struct alias_link needle = {
1093 .src_addr = src_addr,
1094 .src_port = src_port,
1095 .link_type = link_type
1096 };
1097 LIBALIAS_LOCK_ASSERT(la);
1098 return SPLAY_FIND(splay_internal_endpoint, &la->linkSplayInternalEndpoint, &needle);
1099 }
1100
1101 /* External routines for finding/adding links
1102
1103 -- "external" means outside alias_db.c, but within alias*.c --
1104
1105 FindIcmpIn(), FindIcmpOut()
1106 FindFragmentIn1(), FindFragmentIn2()
1107 AddFragmentPtrLink(), FindFragmentPtr()
1108 FindProtoIn(), FindProtoOut()
1109 FindUdpTcpIn(), FindUdpTcpOut()
1110 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1111 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1112 FindOriginalAddress(), FindAliasAddress()
1113
1114 (prototypes in alias_local.h)
1115 */
1116
1117 int
FindIcmpIn(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short id_alias,int create,struct alias_link ** lnkp)1118 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1119 struct in_addr alias_addr,
1120 u_short id_alias,
1121 int create,
1122 struct alias_link **lnkp)
1123 {
1124 struct alias_link *lnk;
1125
1126 LIBALIAS_LOCK_ASSERT(la);
1127
1128 *lnkp = NULL;
1129
1130 lnk = FindLinkIn(la, dst_addr, alias_addr,
1131 NO_DEST_PORT, id_alias,
1132 LINK_ICMP, 0);
1133 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1134 struct in_addr target_addr;
1135
1136 target_addr = FindOriginalAddress(la, alias_addr);
1137 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1138 id_alias, NO_DEST_PORT, id_alias,
1139 LINK_ICMP);
1140 if (lnk == NULL)
1141 return (PKT_ALIAS_ERROR);
1142 }
1143 *lnkp = lnk;
1144 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1145 }
1146
1147 int
FindIcmpOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short id,int create,struct alias_link ** lnkp)1148 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1149 struct in_addr dst_addr,
1150 u_short id,
1151 int create,
1152 struct alias_link **lnkp)
1153 {
1154 struct alias_link *lnk;
1155
1156 LIBALIAS_LOCK_ASSERT(la);
1157
1158 *lnkp = NULL;
1159
1160 lnk = FindLinkOut(la, src_addr, dst_addr,
1161 id, NO_DEST_PORT,
1162 LINK_ICMP, 0);
1163 if (lnk == NULL && create) {
1164 struct in_addr alias_addr;
1165
1166 alias_addr = FindAliasAddress(la, src_addr);
1167 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1168 id, NO_DEST_PORT, GET_ALIAS_ID,
1169 LINK_ICMP);
1170 if (lnk == NULL)
1171 return (PKT_ALIAS_ERROR);
1172 }
1173 *lnkp = lnk;
1174 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1175 }
1176
1177 struct alias_link *
FindFragmentIn1(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short ip_id)1178 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1179 struct in_addr alias_addr,
1180 u_short ip_id)
1181 {
1182 struct alias_link *lnk;
1183
1184 LIBALIAS_LOCK_ASSERT(la);
1185 lnk = FindLinkIn(la, dst_addr, alias_addr,
1186 NO_DEST_PORT, ip_id,
1187 LINK_FRAGMENT_ID, 0);
1188
1189 if (lnk == NULL) {
1190 lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
1191 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1192 LINK_FRAGMENT_ID);
1193 }
1194 return (lnk);
1195 }
1196
1197 /* Doesn't add a link if one is not found. */
1198 struct alias_link *
FindFragmentIn2(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short ip_id)1199 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
1200 struct in_addr alias_addr, u_short ip_id)
1201 {
1202 LIBALIAS_LOCK_ASSERT(la);
1203 return FindLinkIn(la, dst_addr, alias_addr,
1204 NO_DEST_PORT, ip_id,
1205 LINK_FRAGMENT_ID, 0);
1206 }
1207
1208 struct alias_link *
AddFragmentPtrLink(struct libalias * la,struct in_addr dst_addr,u_short ip_id)1209 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1210 u_short ip_id)
1211 {
1212 LIBALIAS_LOCK_ASSERT(la);
1213 return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
1214 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1215 LINK_FRAGMENT_PTR);
1216 }
1217
1218 struct alias_link *
FindFragmentPtr(struct libalias * la,struct in_addr dst_addr,u_short ip_id)1219 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1220 u_short ip_id)
1221 {
1222 LIBALIAS_LOCK_ASSERT(la);
1223 return FindLinkIn(la, dst_addr, ANY_ADDR,
1224 NO_DEST_PORT, ip_id,
1225 LINK_FRAGMENT_PTR, 0);
1226 }
1227
1228 int
FindProtoIn(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_char proto,struct alias_link ** lnkp)1229 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1230 struct in_addr alias_addr,
1231 u_char proto,
1232 struct alias_link **lnkp)
1233 {
1234 struct alias_link *lnk;
1235
1236 LIBALIAS_LOCK_ASSERT(la);
1237
1238 *lnkp = NULL;
1239
1240 lnk = FindLinkIn(la, dst_addr, alias_addr,
1241 NO_DEST_PORT, 0,
1242 proto, 1);
1243 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1244 struct in_addr target_addr;
1245
1246 target_addr = FindOriginalAddress(la, alias_addr);
1247 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1248 NO_SRC_PORT, NO_DEST_PORT, 0,
1249 proto);
1250 if (lnk == NULL)
1251 return (PKT_ALIAS_ERROR);
1252 }
1253 *lnkp = lnk;
1254 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1255 }
1256
1257 int
FindProtoOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_char proto,struct alias_link ** lnkp)1258 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1259 struct in_addr dst_addr,
1260 u_char proto,
1261 struct alias_link **lnkp)
1262 {
1263 struct alias_link *lnk;
1264
1265 LIBALIAS_LOCK_ASSERT(la);
1266
1267 *lnkp = NULL;
1268
1269 lnk = FindLinkOut(la, src_addr, dst_addr,
1270 NO_SRC_PORT, NO_DEST_PORT,
1271 proto, 1);
1272 if (lnk == NULL) {
1273 struct in_addr alias_addr;
1274
1275 alias_addr = FindAliasAddress(la, src_addr);
1276 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1277 NO_SRC_PORT, NO_DEST_PORT, 0,
1278 proto);
1279 if (lnk == NULL)
1280 return (PKT_ALIAS_ERROR);
1281 }
1282 *lnkp = lnk;
1283 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1284 }
1285
1286 int
FindUdpTcpIn(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_short dst_port,u_short alias_port,u_char proto,int create,struct alias_link ** lnkp)1287 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1288 struct in_addr alias_addr,
1289 u_short dst_port,
1290 u_short alias_port,
1291 u_char proto,
1292 int create,
1293 struct alias_link **lnkp)
1294 {
1295 int link_type;
1296 struct alias_link *lnk;
1297
1298 LIBALIAS_LOCK_ASSERT(la);
1299
1300 *lnkp = NULL;
1301
1302 switch (proto) {
1303 case IPPROTO_UDP:
1304 link_type = LINK_UDP;
1305 break;
1306 case IPPROTO_TCP:
1307 link_type = LINK_TCP;
1308 break;
1309 default:
1310 return (PKT_ALIAS_IGNORED);
1311 }
1312
1313 lnk = FindLinkIn(la, dst_addr, alias_addr,
1314 dst_port, alias_port,
1315 link_type, create);
1316
1317 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1318 struct in_addr target_addr;
1319
1320 target_addr = FindOriginalAddress(la, alias_addr);
1321 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1322 alias_port, dst_port, alias_port,
1323 link_type);
1324 if (lnk == NULL)
1325 return (PKT_ALIAS_ERROR);
1326
1327 }
1328 *lnkp = lnk;
1329 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1330 }
1331
1332 int
FindUdpTcpOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short src_port,u_short dst_port,u_char proto,int create,struct alias_link ** lnkp)1333 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1334 struct in_addr dst_addr,
1335 u_short src_port,
1336 u_short dst_port,
1337 u_char proto,
1338 int create,
1339 struct alias_link **lnkp)
1340 {
1341 int link_type;
1342 struct alias_link *lnk;
1343
1344 LIBALIAS_LOCK_ASSERT(la);
1345
1346 *lnkp = NULL;
1347
1348 switch (proto) {
1349 case IPPROTO_UDP:
1350 link_type = LINK_UDP;
1351 break;
1352 case IPPROTO_TCP:
1353 link_type = LINK_TCP;
1354 break;
1355 default:
1356 return (PKT_ALIAS_IGNORED);
1357 }
1358
1359 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1360 if (lnk == NULL && create) {
1361 struct in_addr alias_addr;
1362
1363 alias_addr = FindAliasAddress(la, src_addr);
1364 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1365 src_port, dst_port, GET_ALIAS_PORT,
1366 link_type);
1367 if (lnk == NULL)
1368 return (PKT_ALIAS_ERROR);
1369 }
1370 *lnkp = lnk;
1371 return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
1372 }
1373
1374 struct alias_link *
AddPptp(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,struct in_addr alias_addr,u_int16_t src_call_id)1375 AddPptp(struct libalias *la, struct in_addr src_addr,
1376 struct in_addr dst_addr,
1377 struct in_addr alias_addr,
1378 u_int16_t src_call_id)
1379 {
1380 struct alias_link *lnk;
1381
1382 LIBALIAS_LOCK_ASSERT(la);
1383 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1384 src_call_id, 0, GET_ALIAS_PORT,
1385 LINK_PPTP);
1386
1387 return (lnk);
1388 }
1389
1390 struct alias_link *
FindPptpOutByCallId(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_int16_t src_call_id)1391 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1392 struct in_addr dst_addr,
1393 u_int16_t src_call_id)
1394 {
1395 struct alias_link *lnk;
1396
1397 LIBALIAS_LOCK_ASSERT(la);
1398 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1399 if (lnk->src_addr.s_addr == src_addr.s_addr &&
1400 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1401 lnk->src_port == src_call_id)
1402 break;
1403
1404 return (UseLink(la, lnk));
1405 }
1406
1407 struct alias_link *
FindPptpOutByPeerCallId(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_int16_t dst_call_id)1408 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1409 struct in_addr dst_addr,
1410 u_int16_t dst_call_id)
1411 {
1412 struct alias_link *lnk;
1413
1414 LIBALIAS_LOCK_ASSERT(la);
1415 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1416 if (lnk->src_addr.s_addr == src_addr.s_addr &&
1417 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1418 lnk->dst_port == dst_call_id)
1419 break;
1420
1421 return (UseLink(la, lnk));
1422 }
1423
1424 struct alias_link *
FindPptpInByCallId(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_int16_t dst_call_id)1425 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1426 struct in_addr alias_addr,
1427 u_int16_t dst_call_id)
1428 {
1429 struct alias_link *lnk;
1430
1431 LIBALIAS_LOCK_ASSERT(la);
1432
1433 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1434 if (lnk->dst_port == dst_call_id &&
1435 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1436 lnk->alias_addr.s_addr == alias_addr.s_addr)
1437 break;
1438
1439 return (UseLink(la, lnk));
1440 }
1441
1442 struct alias_link *
FindPptpInByPeerCallId(struct libalias * la,struct in_addr dst_addr,struct in_addr alias_addr,u_int16_t alias_call_id)1443 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1444 struct in_addr alias_addr,
1445 u_int16_t alias_call_id)
1446 {
1447 struct alias_link *lnk;
1448
1449 LIBALIAS_LOCK_ASSERT(la);
1450 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1451 if (lnk->alias_port == alias_call_id &&
1452 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1453 lnk->alias_addr.s_addr == alias_addr.s_addr)
1454 break;
1455
1456 return (lnk);
1457 }
1458
1459 struct alias_link *
FindRtspOut(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,u_short src_port,u_short alias_port,u_char proto)1460 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1461 struct in_addr dst_addr,
1462 u_short src_port,
1463 u_short alias_port,
1464 u_char proto)
1465 {
1466 int link_type;
1467 struct alias_link *lnk;
1468
1469 LIBALIAS_LOCK_ASSERT(la);
1470 switch (proto) {
1471 case IPPROTO_UDP:
1472 link_type = LINK_UDP;
1473 break;
1474 case IPPROTO_TCP:
1475 link_type = LINK_TCP;
1476 break;
1477 default:
1478 return (NULL);
1479 break;
1480 }
1481
1482 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1483
1484 if (lnk == NULL) {
1485 struct in_addr alias_addr;
1486
1487 alias_addr = FindAliasAddress(la, src_addr);
1488 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1489 src_port, 0, alias_port,
1490 link_type);
1491 }
1492 return (lnk);
1493 }
1494
1495 struct in_addr
FindOriginalAddress(struct libalias * la,struct in_addr alias_addr)1496 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1497 {
1498 struct alias_link *lnk;
1499
1500 LIBALIAS_LOCK_ASSERT(la);
1501 lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
1502 0, 0, LINK_ADDR, 0);
1503 if (lnk == NULL) {
1504 if (la->targetAddress.s_addr == INADDR_ANY)
1505 return (alias_addr);
1506 else if (la->targetAddress.s_addr == INADDR_NONE)
1507 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1508 la->aliasAddress : alias_addr;
1509 else
1510 return (la->targetAddress);
1511 } else {
1512 if (lnk->server != NULL) { /* LSNAT link */
1513 struct in_addr src_addr;
1514
1515 src_addr = lnk->server->addr;
1516 lnk->server = lnk->server->next;
1517 return (src_addr);
1518 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1519 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1520 la->aliasAddress : alias_addr;
1521 else
1522 return (lnk->src_addr);
1523 }
1524 }
1525
1526 struct in_addr
FindAliasAddress(struct libalias * la,struct in_addr original_addr)1527 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1528 {
1529 struct alias_link *lnk;
1530
1531 LIBALIAS_LOCK_ASSERT(la);
1532 lnk = FindLinkOut(la, original_addr, ANY_ADDR,
1533 0, 0, LINK_ADDR, 0);
1534 if (lnk == NULL) {
1535 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1536 la->aliasAddress : original_addr;
1537 } else {
1538 if (lnk->alias_addr.s_addr == INADDR_ANY)
1539 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1540 la->aliasAddress : original_addr;
1541 else
1542 return (lnk->alias_addr);
1543 }
1544 }
1545
1546 /* External routines for getting or changing link data
1547 (external to alias_db.c, but internal to alias*.c)
1548
1549 SetFragmentData(), GetFragmentData()
1550 SetFragmentPtr(), GetFragmentPtr()
1551 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1552 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1553 GetOriginalPort(), GetAliasPort()
1554 SetAckModified(), GetAckModified()
1555 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1556 SetProtocolFlags(), GetProtocolFlags()
1557 SetDestCallId()
1558 */
1559
1560 void
SetFragmentAddr(struct alias_link * lnk,struct in_addr src_addr)1561 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1562 {
1563 lnk->data.frag_addr = src_addr;
1564 }
1565
1566 void
GetFragmentAddr(struct alias_link * lnk,struct in_addr * src_addr)1567 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1568 {
1569 *src_addr = lnk->data.frag_addr;
1570 }
1571
1572 void
SetFragmentPtr(struct alias_link * lnk,void * fptr)1573 SetFragmentPtr(struct alias_link *lnk, void *fptr)
1574 {
1575 lnk->data.frag_ptr = fptr;
1576 }
1577
1578 void
GetFragmentPtr(struct alias_link * lnk,void ** fptr)1579 GetFragmentPtr(struct alias_link *lnk, void **fptr)
1580 {
1581 *fptr = lnk->data.frag_ptr;
1582 }
1583
1584 void
SetStateIn(struct alias_link * lnk,int state)1585 SetStateIn(struct alias_link *lnk, int state)
1586 {
1587 /* TCP input state */
1588 switch (state) {
1589 case ALIAS_TCP_STATE_DISCONNECTED:
1590 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1591 lnk->expire.time = TCP_EXPIRE_DEAD;
1592 else
1593 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1594 break;
1595 case ALIAS_TCP_STATE_CONNECTED:
1596 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1597 lnk->expire.time = TCP_EXPIRE_CONNECTED;
1598 break;
1599 default:
1600 #ifdef _KERNEL
1601 panic("libalias:SetStateIn() unknown state");
1602 #else
1603 abort();
1604 #endif
1605 }
1606 lnk->data.tcp->state.in = state;
1607 }
1608
1609 void
SetStateOut(struct alias_link * lnk,int state)1610 SetStateOut(struct alias_link *lnk, int state)
1611 {
1612 /* TCP output state */
1613 switch (state) {
1614 case ALIAS_TCP_STATE_DISCONNECTED:
1615 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1616 lnk->expire.time = TCP_EXPIRE_DEAD;
1617 else
1618 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1619 break;
1620 case ALIAS_TCP_STATE_CONNECTED:
1621 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1622 lnk->expire.time = TCP_EXPIRE_CONNECTED;
1623 break;
1624 default:
1625 #ifdef _KERNEL
1626 panic("libalias:SetStateOut() unknown state");
1627 #else
1628 abort();
1629 #endif
1630 }
1631 lnk->data.tcp->state.out = state;
1632 }
1633
1634 int
GetStateIn(struct alias_link * lnk)1635 GetStateIn(struct alias_link *lnk)
1636 {
1637 /* TCP input state */
1638 return (lnk->data.tcp->state.in);
1639 }
1640
1641 int
GetStateOut(struct alias_link * lnk)1642 GetStateOut(struct alias_link *lnk)
1643 {
1644 /* TCP output state */
1645 return (lnk->data.tcp->state.out);
1646 }
1647
1648 struct in_addr
GetOriginalAddress(struct alias_link * lnk)1649 GetOriginalAddress(struct alias_link *lnk)
1650 {
1651 if (lnk->src_addr.s_addr == INADDR_ANY)
1652 return (lnk->la->aliasAddress);
1653 else
1654 return (lnk->src_addr);
1655 }
1656
1657 struct in_addr
GetDestAddress(struct alias_link * lnk)1658 GetDestAddress(struct alias_link *lnk)
1659 {
1660 return (lnk->dst_addr);
1661 }
1662
1663 struct in_addr
GetAliasAddress(struct alias_link * lnk)1664 GetAliasAddress(struct alias_link *lnk)
1665 {
1666 if (lnk->alias_addr.s_addr == INADDR_ANY)
1667 return (lnk->la->aliasAddress);
1668 else
1669 return (lnk->alias_addr);
1670 }
1671
1672 struct in_addr
GetDefaultAliasAddress(struct libalias * la)1673 GetDefaultAliasAddress(struct libalias *la)
1674 {
1675 LIBALIAS_LOCK_ASSERT(la);
1676 return (la->aliasAddress);
1677 }
1678
1679 void
SetDefaultAliasAddress(struct libalias * la,struct in_addr alias_addr)1680 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1681 {
1682 LIBALIAS_LOCK_ASSERT(la);
1683 la->aliasAddress = alias_addr;
1684 }
1685
1686 u_short
GetOriginalPort(struct alias_link * lnk)1687 GetOriginalPort(struct alias_link *lnk)
1688 {
1689 return (lnk->src_port);
1690 }
1691
1692 u_short
GetAliasPort(struct alias_link * lnk)1693 GetAliasPort(struct alias_link *lnk)
1694 {
1695 return (lnk->alias_port);
1696 }
1697
1698 #ifndef NO_FW_PUNCH
1699 static u_short
GetDestPort(struct alias_link * lnk)1700 GetDestPort(struct alias_link *lnk)
1701 {
1702 return (lnk->dst_port);
1703 }
1704
1705 #endif
1706
1707 /* Indicate that ACK numbers have been modified in a TCP connection */
1708 void
SetAckModified(struct alias_link * lnk)1709 SetAckModified(struct alias_link *lnk)
1710 {
1711 lnk->data.tcp->state.ack_modified = 1;
1712 }
1713
1714 struct in_addr
GetProxyAddress(struct alias_link * lnk)1715 GetProxyAddress(struct alias_link *lnk)
1716 {
1717 return (lnk->proxy_addr);
1718 }
1719
1720 void
SetProxyAddress(struct alias_link * lnk,struct in_addr addr)1721 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1722 {
1723 lnk->proxy_addr = addr;
1724 }
1725
1726 u_short
GetProxyPort(struct alias_link * lnk)1727 GetProxyPort(struct alias_link *lnk)
1728 {
1729 return (lnk->proxy_port);
1730 }
1731
1732 void
SetProxyPort(struct alias_link * lnk,u_short port)1733 SetProxyPort(struct alias_link *lnk, u_short port)
1734 {
1735 lnk->proxy_port = port;
1736 }
1737
1738 /* See if ACK numbers have been modified */
1739 int
GetAckModified(struct alias_link * lnk)1740 GetAckModified(struct alias_link *lnk)
1741 {
1742 return (lnk->data.tcp->state.ack_modified);
1743 }
1744
1745 /*
1746 * Find out how much the ACK number has been altered for an
1747 * incoming TCP packet. To do this, a circular list of ACK
1748 * numbers where the TCP packet size was altered is searched.
1749 */
1750 // XXX ip free
1751 int
GetDeltaAckIn(u_long ack,struct alias_link * lnk)1752 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1753 {
1754 int i, j;
1755 int delta, ack_diff_min;
1756
1757 delta = 0;
1758 ack_diff_min = -1;
1759 i = lnk->data.tcp->state.index;
1760 for (j = 0; j < N_LINK_TCP_DATA; j++) {
1761 struct ack_data_record x;
1762
1763 if (i == 0)
1764 i = N_LINK_TCP_DATA;
1765 i--;
1766 x = lnk->data.tcp->ack[i];
1767 if (x.active == 1) {
1768 int ack_diff;
1769
1770 ack_diff = SeqDiff(x.ack_new, ack);
1771 if (ack_diff >= 0) {
1772 if (ack_diff_min >= 0) {
1773 if (ack_diff < ack_diff_min) {
1774 delta = x.delta;
1775 ack_diff_min = ack_diff;
1776 }
1777 } else {
1778 delta = x.delta;
1779 ack_diff_min = ack_diff;
1780 }
1781 }
1782 }
1783 }
1784 return (delta);
1785 }
1786
1787 /*
1788 * Find out how much the sequence number has been altered for an
1789 * outgoing TCP packet. To do this, a circular list of ACK numbers
1790 * where the TCP packet size was altered is searched.
1791 */
1792 // XXX ip free
1793 int
GetDeltaSeqOut(u_long seq,struct alias_link * lnk)1794 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1795 {
1796 int i, j;
1797 int delta, seq_diff_min;
1798
1799 delta = 0;
1800 seq_diff_min = -1;
1801 i = lnk->data.tcp->state.index;
1802 for (j = 0; j < N_LINK_TCP_DATA; j++) {
1803 struct ack_data_record x;
1804
1805 if (i == 0)
1806 i = N_LINK_TCP_DATA;
1807 i--;
1808 x = lnk->data.tcp->ack[i];
1809 if (x.active == 1) {
1810 int seq_diff;
1811
1812 seq_diff = SeqDiff(x.ack_old, seq);
1813 if (seq_diff >= 0) {
1814 if (seq_diff_min >= 0) {
1815 if (seq_diff < seq_diff_min) {
1816 delta = x.delta;
1817 seq_diff_min = seq_diff;
1818 }
1819 } else {
1820 delta = x.delta;
1821 seq_diff_min = seq_diff;
1822 }
1823 }
1824 }
1825 }
1826 return (delta);
1827 }
1828
1829 /*
1830 * When a TCP packet has been altered in length, save this
1831 * information in a circular list. If enough packets have been
1832 * altered, then this list will begin to overwrite itself.
1833 */
1834 // XXX ip free
1835 void
AddSeq(struct alias_link * lnk,int delta,u_int ip_hl,u_short ip_len,u_long th_seq,u_int th_off)1836 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
1837 u_long th_seq, u_int th_off)
1838 {
1839 struct ack_data_record x;
1840 int hlen, tlen, dlen;
1841 int i;
1842
1843 hlen = (ip_hl + th_off) << 2;
1844 tlen = ntohs(ip_len);
1845 dlen = tlen - hlen;
1846
1847 x.ack_old = htonl(ntohl(th_seq) + dlen);
1848 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
1849 x.delta = delta;
1850 x.active = 1;
1851
1852 i = lnk->data.tcp->state.index;
1853 lnk->data.tcp->ack[i] = x;
1854
1855 i++;
1856 if (i == N_LINK_TCP_DATA)
1857 lnk->data.tcp->state.index = 0;
1858 else
1859 lnk->data.tcp->state.index = i;
1860 }
1861
1862 void
SetExpire(struct alias_link * lnk,int expire)1863 SetExpire(struct alias_link *lnk, int expire)
1864 {
1865 if (expire == 0) {
1866 lnk->flags &= ~LINK_PERMANENT;
1867 DeleteLink(&lnk, 0);
1868 } else if (expire == -1) {
1869 lnk->flags |= LINK_PERMANENT;
1870 } else if (expire > 0) {
1871 lnk->expire.time = expire;
1872 } else {
1873 #ifdef LIBALIAS_DEBUG
1874 fprintf(stderr, "PacketAlias/SetExpire(): ");
1875 fprintf(stderr, "error in expire parameter\n");
1876 #endif
1877 }
1878 }
1879
1880 void
SetProtocolFlags(struct alias_link * lnk,int pflags)1881 SetProtocolFlags(struct alias_link *lnk, int pflags)
1882 {
1883 lnk->pflags = pflags;
1884 }
1885
1886 int
GetProtocolFlags(struct alias_link * lnk)1887 GetProtocolFlags(struct alias_link *lnk)
1888 {
1889 return (lnk->pflags);
1890 }
1891
1892 void
SetDestCallId(struct alias_link * lnk,u_int16_t cid)1893 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
1894 {
1895 LIBALIAS_LOCK_ASSERT(lnk->la);
1896 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
1897 lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
1898 }
1899
1900 /* Miscellaneous Functions
1901
1902 HouseKeeping()
1903 InitPacketAliasLog()
1904 UninitPacketAliasLog()
1905 */
1906
1907 /*
1908 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1909 is called to find and remove timed-out aliasing links. Logic exists
1910 to sweep through the entire table and linked list structure
1911 every 60 seconds.
1912
1913 (prototype in alias_local.h)
1914 */
1915
1916 void
HouseKeeping(struct libalias * la)1917 HouseKeeping(struct libalias *la)
1918 {
1919 static unsigned int packets = 0;
1920 static unsigned int packet_limit = 1000;
1921
1922 LIBALIAS_LOCK_ASSERT(la);
1923 packets++;
1924
1925 /*
1926 * User space time/gettimeofday/... is very expensive.
1927 * Kernel space cache trashing is unnecessary.
1928 *
1929 * Save system time (seconds) in global variable LibAliasTime
1930 * for use by other functions. This is done so as not to
1931 * unnecessarily waste timeline by making system calls.
1932 *
1933 * Reduce the amount of house keeping work substantially by
1934 * sampling over the packets.
1935 */
1936 if (packet_limit <= 1 || packets % packet_limit == 0) {
1937 time_t now;
1938
1939 #ifdef _KERNEL
1940 now = time_uptime;
1941 #else
1942 now = time(NULL);
1943 #endif
1944 if (now != LibAliasTime) {
1945 /* retry three times a second */
1946 packet_limit = packets / 3;
1947 packets = 0;
1948 LibAliasTime = now;
1949 }
1950
1951 }
1952 /* Do a cleanup for the first packets of the new second only */
1953 if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
1954 struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
1955
1956 CleanupLink(la, &lnk, 0);
1957 }
1958 }
1959
1960 /* Init the log file and enable logging */
1961 static int
InitPacketAliasLog(struct libalias * la)1962 InitPacketAliasLog(struct libalias *la)
1963 {
1964 LIBALIAS_LOCK_ASSERT(la);
1965 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
1966 #ifdef _KERNEL
1967 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
1968 ;
1969 #else
1970 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
1971 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1972 #endif
1973 else
1974 return (ENOMEM); /* log initialization failed */
1975 la->packetAliasMode |= PKT_ALIAS_LOG;
1976 }
1977
1978 return (1);
1979 }
1980
1981 /* Close the log-file and disable logging. */
1982 static void
UninitPacketAliasLog(struct libalias * la)1983 UninitPacketAliasLog(struct libalias *la)
1984 {
1985 LIBALIAS_LOCK_ASSERT(la);
1986 if (la->logDesc) {
1987 #ifdef _KERNEL
1988 free(la->logDesc);
1989 #else
1990 fclose(la->logDesc);
1991 #endif
1992 la->logDesc = NULL;
1993 }
1994 la->packetAliasMode &= ~PKT_ALIAS_LOG;
1995 }
1996
1997 /* Outside world interfaces
1998
1999 -- "outside world" means other than alias*.c routines --
2000
2001 PacketAliasRedirectPort()
2002 PacketAliasAddServer()
2003 PacketAliasRedirectProto()
2004 PacketAliasRedirectAddr()
2005 PacketAliasRedirectDynamic()
2006 PacketAliasRedirectDelete()
2007 PacketAliasSetAddress()
2008 PacketAliasInit()
2009 PacketAliasUninit()
2010 PacketAliasSetMode()
2011
2012 (prototypes in alias.h)
2013 */
2014
2015 /* Redirection from a specific public addr:port to a
2016 private addr:port */
2017 struct alias_link *
LibAliasRedirectPort(struct libalias * la,struct in_addr src_addr,u_short src_port,struct in_addr dst_addr,u_short dst_port,struct in_addr alias_addr,u_short alias_port,u_char proto)2018 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2019 struct in_addr dst_addr, u_short dst_port,
2020 struct in_addr alias_addr, u_short alias_port,
2021 u_char proto)
2022 {
2023 int link_type;
2024 struct alias_link *lnk;
2025
2026 LIBALIAS_LOCK(la);
2027 switch (proto) {
2028 case IPPROTO_UDP:
2029 link_type = LINK_UDP;
2030 break;
2031 case IPPROTO_TCP:
2032 link_type = LINK_TCP;
2033 break;
2034 case IPPROTO_SCTP:
2035 link_type = LINK_SCTP;
2036 break;
2037 default:
2038 #ifdef LIBALIAS_DEBUG
2039 fprintf(stderr, "PacketAliasRedirectPort(): ");
2040 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2041 #endif
2042 lnk = NULL;
2043 goto getout;
2044 }
2045
2046 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2047 src_port, dst_port, alias_port,
2048 link_type);
2049
2050 if (lnk != NULL) {
2051 lnk->flags |= LINK_PERMANENT;
2052 }
2053 #ifdef LIBALIAS_DEBUG
2054 else {
2055 fprintf(stderr, "PacketAliasRedirectPort(): "
2056 "call to AddLink() failed\n");
2057 }
2058 #endif
2059
2060 getout:
2061 LIBALIAS_UNLOCK(la);
2062 return (lnk);
2063 }
2064
2065 /* Add server to the pool of servers */
2066 int
LibAliasAddServer(struct libalias * la,struct alias_link * lnk,struct in_addr addr,u_short port)2067 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2068 {
2069 struct server *server;
2070 int res;
2071
2072 LIBALIAS_LOCK(la);
2073 (void)la;
2074
2075 switch (lnk->link_type) {
2076 case LINK_PPTP:
2077 server = NULL;
2078 break;
2079 default:
2080 server = malloc(sizeof(struct server));
2081 break;
2082 }
2083
2084 if (server != NULL) {
2085 struct server *head;
2086
2087 server->addr = addr;
2088 server->port = port;
2089
2090 head = lnk->server;
2091 if (head == NULL) {
2092 server->next = server;
2093 /* not usable for outgoing connections */
2094 SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
2095 } else {
2096 struct server *s;
2097
2098 for (s = head; s->next != head; s = s->next)
2099 ;
2100 s->next = server;
2101 server->next = head;
2102 }
2103 lnk->server = server;
2104 res = 0;
2105 } else
2106 res = -1;
2107
2108 LIBALIAS_UNLOCK(la);
2109 return (res);
2110 }
2111
2112 /* Redirect packets of a given IP protocol from a specific
2113 public address to a private address */
2114 struct alias_link *
LibAliasRedirectProto(struct libalias * la,struct in_addr src_addr,struct in_addr dst_addr,struct in_addr alias_addr,u_char proto)2115 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2116 struct in_addr dst_addr,
2117 struct in_addr alias_addr,
2118 u_char proto)
2119 {
2120 struct alias_link *lnk;
2121
2122 LIBALIAS_LOCK(la);
2123 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2124 NO_SRC_PORT, NO_DEST_PORT, 0,
2125 proto);
2126
2127 if (lnk != NULL) {
2128 lnk->flags |= LINK_PERMANENT;
2129 }
2130 #ifdef LIBALIAS_DEBUG
2131 else {
2132 fprintf(stderr, "PacketAliasRedirectProto(): "
2133 "call to AddLink() failed\n");
2134 }
2135 #endif
2136
2137 LIBALIAS_UNLOCK(la);
2138 return (lnk);
2139 }
2140
2141 /* Static address translation */
2142 struct alias_link *
LibAliasRedirectAddr(struct libalias * la,struct in_addr src_addr,struct in_addr alias_addr)2143 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2144 struct in_addr alias_addr)
2145 {
2146 struct alias_link *lnk;
2147
2148 LIBALIAS_LOCK(la);
2149 lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
2150 0, 0, 0,
2151 LINK_ADDR);
2152
2153 if (lnk != NULL) {
2154 lnk->flags |= LINK_PERMANENT;
2155 }
2156 #ifdef LIBALIAS_DEBUG
2157 else {
2158 fprintf(stderr, "PacketAliasRedirectAddr(): "
2159 "call to AddLink() failed\n");
2160 }
2161 #endif
2162
2163 LIBALIAS_UNLOCK(la);
2164 return (lnk);
2165 }
2166
2167 /* Mark the aliasing link dynamic */
2168 int
LibAliasRedirectDynamic(struct libalias * la,struct alias_link * lnk)2169 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2170 {
2171 int res;
2172
2173 LIBALIAS_LOCK(la);
2174 (void)la;
2175
2176 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2177 res = -1;
2178 else {
2179 lnk->flags &= ~LINK_PERMANENT;
2180 res = 0;
2181 }
2182 LIBALIAS_UNLOCK(la);
2183 return (res);
2184 }
2185
2186 /* This is a dangerous function to put in the API,
2187 because an invalid pointer can crash the program. */
2188 void
LibAliasRedirectDelete(struct libalias * la,struct alias_link * lnk)2189 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2190 {
2191 LIBALIAS_LOCK(la);
2192 (void)la;
2193 DeleteLink(&lnk, 1);
2194 LIBALIAS_UNLOCK(la);
2195 }
2196
2197 void
LibAliasSetAddress(struct libalias * la,struct in_addr addr)2198 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2199 {
2200 LIBALIAS_LOCK(la);
2201 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2202 && la->aliasAddress.s_addr != addr.s_addr)
2203 CleanupAliasData(la, 0);
2204
2205 la->aliasAddress = addr;
2206 LIBALIAS_UNLOCK(la);
2207 }
2208
2209 void
LibAliasSetAliasPortRange(struct libalias * la,u_short port_low,u_short port_high)2210 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2211 u_short port_high)
2212 {
2213 LIBALIAS_LOCK(la);
2214 if (port_low) {
2215 la->aliasPortLower = port_low;
2216 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2217 la->aliasPortLength = port_high - port_low + 1;
2218 } else {
2219 /* Set default values */
2220 la->aliasPortLower = 0x8000;
2221 la->aliasPortLength = 0x8000;
2222 }
2223 LIBALIAS_UNLOCK(la);
2224 }
2225
2226 void
LibAliasSetTarget(struct libalias * la,struct in_addr target_addr)2227 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2228 {
2229 LIBALIAS_LOCK(la);
2230 la->targetAddress = target_addr;
2231 LIBALIAS_UNLOCK(la);
2232 }
2233
2234 static void
finishoff(void)2235 finishoff(void)
2236 {
2237 while (!LIST_EMPTY(&instancehead))
2238 LibAliasUninit(LIST_FIRST(&instancehead));
2239 }
2240
2241 struct libalias *
LibAliasInit(struct libalias * la)2242 LibAliasInit(struct libalias *la)
2243 {
2244 if (la == NULL) {
2245 #ifdef _KERNEL
2246 #undef malloc /* XXX: ugly */
2247 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2248 #else
2249 la = calloc(1, sizeof *la);
2250 if (la == NULL)
2251 return (la);
2252 #endif
2253
2254 #ifndef _KERNEL
2255 /* kernel cleans up on module unload */
2256 if (LIST_EMPTY(&instancehead))
2257 atexit(finishoff);
2258 #endif
2259 #ifdef _KERNEL
2260 mtx_lock(&list_mtx);
2261 #endif
2262 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2263 #ifdef _KERNEL
2264 mtx_unlock(&list_mtx);
2265 #endif
2266
2267 #ifdef _KERNEL
2268 LibAliasTime = time_uptime;
2269 #else
2270 LibAliasTime = time(NULL);
2271 #endif
2272
2273 SPLAY_INIT(&la->linkSplayIn);
2274 SPLAY_INIT(&la->linkSplayOut);
2275 SPLAY_INIT(&la->linkSplayInternalEndpoint);
2276 LIST_INIT(&la->pptpList);
2277 TAILQ_INIT(&la->checkExpire);
2278 #ifdef _KERNEL
2279 AliasSctpInit(la);
2280 #endif
2281 LIBALIAS_LOCK_INIT(la);
2282 LIBALIAS_LOCK(la);
2283 } else {
2284 LIBALIAS_LOCK(la);
2285 CleanupAliasData(la, 1);
2286 #ifdef _KERNEL
2287 AliasSctpTerm(la);
2288 AliasSctpInit(la);
2289 #endif
2290 }
2291
2292 la->aliasAddress.s_addr = INADDR_ANY;
2293 la->targetAddress.s_addr = INADDR_ANY;
2294 la->aliasPortLower = 0x8000;
2295 la->aliasPortLength = 0x8000;
2296
2297 la->icmpLinkCount = 0;
2298 la->udpLinkCount = 0;
2299 la->tcpLinkCount = 0;
2300 la->sctpLinkCount = 0;
2301 la->pptpLinkCount = 0;
2302 la->protoLinkCount = 0;
2303 la->fragmentIdLinkCount = 0;
2304 la->fragmentPtrLinkCount = 0;
2305 la->sockCount = 0;
2306
2307 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2308 #ifndef NO_USE_SOCKETS
2309 | PKT_ALIAS_USE_SOCKETS
2310 #endif
2311 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2312 #ifndef NO_FW_PUNCH
2313 la->fireWallFD = -1;
2314 #endif
2315 #ifndef _KERNEL
2316 LibAliasRefreshModules();
2317 #endif
2318 LIBALIAS_UNLOCK(la);
2319 return (la);
2320 }
2321
2322 void
LibAliasUninit(struct libalias * la)2323 LibAliasUninit(struct libalias *la)
2324 {
2325 LIBALIAS_LOCK(la);
2326 #ifdef _KERNEL
2327 AliasSctpTerm(la);
2328 #endif
2329 CleanupAliasData(la, 1);
2330 UninitPacketAliasLog(la);
2331 #ifndef NO_FW_PUNCH
2332 UninitPunchFW(la);
2333 #endif
2334 #ifdef _KERNEL
2335 mtx_lock(&list_mtx);
2336 #endif
2337 LIST_REMOVE(la, instancelist);
2338 #ifdef _KERNEL
2339 mtx_unlock(&list_mtx);
2340 #endif
2341 LIBALIAS_UNLOCK(la);
2342 LIBALIAS_LOCK_DESTROY(la);
2343 free(la);
2344 }
2345
2346 /* Change mode for some operations */
2347 unsigned int
LibAliasSetMode(struct libalias * la,unsigned int flags,unsigned int mask)2348 LibAliasSetMode(
2349 struct libalias *la,
2350 unsigned int flags, /* Which state to bring flags to */
2351 unsigned int mask /* Mask of which flags to affect (use 0 to
2352 * do a probe for flag values) */
2353 )
2354 {
2355 int res = -1;
2356
2357 LIBALIAS_LOCK(la);
2358 if (flags & mask & PKT_ALIAS_LOG) {
2359 /* Enable logging */
2360 if (InitPacketAliasLog(la) == ENOMEM)
2361 goto getout;
2362 } else if (~flags & mask & PKT_ALIAS_LOG)
2363 /* _Disable_ logging */
2364 UninitPacketAliasLog(la);
2365
2366 #ifndef NO_FW_PUNCH
2367 if (flags & mask & PKT_ALIAS_PUNCH_FW)
2368 /* Start punching holes in the firewall? */
2369 InitPunchFW(la);
2370 else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
2371 /* Stop punching holes in the firewall? */
2372 UninitPunchFW(la);
2373 #endif
2374
2375 /* Other flags can be set/cleared without special action */
2376 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2377 res = la->packetAliasMode;
2378 getout:
2379 LIBALIAS_UNLOCK(la);
2380 return (res);
2381 }
2382
2383 #ifndef NO_FW_PUNCH
2384
2385 /*****************
2386 Code to support firewall punching. This shouldn't really be in this
2387 file, but making variables global is evil too.
2388 ****************/
2389
2390 /* Firewall include files */
2391 #include <net/if.h>
2392 #include <netinet/ip_fw.h>
2393 #include <string.h>
2394 #include <err.h>
2395
2396 /*
2397 * helper function, updates the pointer to cmd with the length
2398 * of the current command, and also cleans up the first word of
2399 * the new command in case it has been clobbered before.
2400 */
2401 static ipfw_insn *
next_cmd(ipfw_insn * cmd)2402 next_cmd(ipfw_insn * cmd)
2403 {
2404 cmd += F_LEN(cmd);
2405 bzero(cmd, sizeof(*cmd));
2406 return (cmd);
2407 }
2408
2409 /*
2410 * A function to fill simple commands of size 1.
2411 * Existing flags are preserved.
2412 */
2413 static ipfw_insn *
fill_cmd(ipfw_insn * cmd,enum ipfw_opcodes opcode,int size,int flags,u_int16_t arg)2414 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2415 int flags, u_int16_t arg)
2416 {
2417 cmd->opcode = opcode;
2418 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2419 cmd->arg1 = arg;
2420 return next_cmd(cmd);
2421 }
2422
2423 static ipfw_insn *
fill_ip(ipfw_insn * cmd1,enum ipfw_opcodes opcode,u_int32_t addr)2424 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2425 {
2426 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2427
2428 cmd->addr.s_addr = addr;
2429 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2430 }
2431
2432 static ipfw_insn *
fill_one_port(ipfw_insn * cmd1,enum ipfw_opcodes opcode,u_int16_t port)2433 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2434 {
2435 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2436
2437 cmd->ports[0] = cmd->ports[1] = port;
2438 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2439 }
2440
2441 static int
fill_rule(void * buf,int bufsize,int rulenum,enum ipfw_opcodes action,int proto,struct in_addr sa,u_int16_t sp,struct in_addr da,u_int16_t dp)2442 fill_rule(void *buf, int bufsize, int rulenum,
2443 enum ipfw_opcodes action, int proto,
2444 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2445 {
2446 struct ip_fw *rule = (struct ip_fw *)buf;
2447 ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2448
2449 bzero(buf, bufsize);
2450 rule->rulenum = rulenum;
2451
2452 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2453 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2454 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2455 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2456 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2457
2458 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2459 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2460
2461 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2462
2463 return ((char *)cmd - (char *)buf);
2464 }
2465
2466 static void
InitPunchFW(struct libalias * la)2467 InitPunchFW(struct libalias *la)
2468 {
2469 la->fireWallField = malloc(la->fireWallNumNums);
2470 if (la->fireWallField) {
2471 memset(la->fireWallField, 0, la->fireWallNumNums);
2472 if (la->fireWallFD < 0) {
2473 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2474 }
2475 ClearAllFWHoles(la);
2476 la->fireWallActiveNum = la->fireWallBaseNum;
2477 }
2478 }
2479
2480 static void
UninitPunchFW(struct libalias * la)2481 UninitPunchFW(struct libalias *la)
2482 {
2483 ClearAllFWHoles(la);
2484 if (la->fireWallFD >= 0)
2485 close(la->fireWallFD);
2486 la->fireWallFD = -1;
2487 if (la->fireWallField)
2488 free(la->fireWallField);
2489 la->fireWallField = NULL;
2490 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2491 }
2492
2493 /* Make a certain link go through the firewall */
2494 void
PunchFWHole(struct alias_link * lnk)2495 PunchFWHole(struct alias_link *lnk)
2496 {
2497 struct libalias *la;
2498 int r; /* Result code */
2499 struct ip_fw rule; /* On-the-fly built rule */
2500 int fwhole; /* Where to punch hole */
2501
2502 la = lnk->la;
2503
2504 /* Don't do anything unless we are asked to */
2505 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2506 la->fireWallFD < 0 ||
2507 lnk->link_type != LINK_TCP)
2508 return;
2509
2510 memset(&rule, 0, sizeof rule);
2511
2512 /** Build rule **/
2513
2514 /* Find empty slot */
2515 for (fwhole = la->fireWallActiveNum;
2516 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2517 fw_tstfield(la, la->fireWallField, fwhole);
2518 fwhole++);
2519 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2520 for (fwhole = la->fireWallBaseNum;
2521 fwhole < la->fireWallActiveNum &&
2522 fw_tstfield(la, la->fireWallField, fwhole);
2523 fwhole++);
2524 if (fwhole == la->fireWallActiveNum) {
2525 /* No rule point empty - we can't punch more holes. */
2526 la->fireWallActiveNum = la->fireWallBaseNum;
2527 #ifdef LIBALIAS_DEBUG
2528 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2529 #endif
2530 return;
2531 }
2532 }
2533 /* Start next search at next position */
2534 la->fireWallActiveNum = fwhole + 1;
2535
2536 /*
2537 * generate two rules of the form
2538 *
2539 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2540 * accept tcp from DAddr DPort to OAddr OPort
2541 */
2542 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2543 u_int32_t rulebuf[255];
2544 int i;
2545
2546 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2547 O_ACCEPT, IPPROTO_TCP,
2548 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2549 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2550 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2551 if (r)
2552 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2553
2554 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2555 O_ACCEPT, IPPROTO_TCP,
2556 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2557 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2558 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2559 if (r)
2560 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2561 }
2562
2563 /* Indicate hole applied */
2564 lnk->data.tcp->fwhole = fwhole;
2565 fw_setfield(la, la->fireWallField, fwhole);
2566 }
2567
2568 /* Remove a hole in a firewall associated with a particular alias
2569 lnk. Calling this too often is harmless. */
2570 static void
ClearFWHole(struct alias_link * lnk)2571 ClearFWHole(struct alias_link *lnk)
2572 {
2573 struct libalias *la;
2574
2575 la = lnk->la;
2576 if (lnk->link_type == LINK_TCP) {
2577 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */
2578 struct ip_fw rule;
2579
2580 if (fwhole < 0)
2581 return;
2582
2583 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2584 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2585 &fwhole, sizeof fwhole));
2586 fw_clrfield(la, la->fireWallField, fwhole);
2587 lnk->data.tcp->fwhole = -1;
2588 }
2589 }
2590
2591 /* Clear out the entire range dedicated to firewall holes. */
2592 static void
ClearAllFWHoles(struct libalias * la)2593 ClearAllFWHoles(struct libalias *la)
2594 {
2595 struct ip_fw rule; /* On-the-fly built rule */
2596 int i;
2597
2598 if (la->fireWallFD < 0)
2599 return;
2600
2601 memset(&rule, 0, sizeof rule);
2602 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2603 int r = i;
2604
2605 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2606 }
2607 /* XXX: third arg correct here ? /phk */
2608 memset(la->fireWallField, 0, la->fireWallNumNums);
2609 }
2610
2611 #endif /* !NO_FW_PUNCH */
2612
2613 void
LibAliasSetFWBase(struct libalias * la,unsigned int base,unsigned int num)2614 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2615 {
2616 LIBALIAS_LOCK(la);
2617 #ifndef NO_FW_PUNCH
2618 la->fireWallBaseNum = base;
2619 la->fireWallNumNums = num;
2620 #endif
2621 LIBALIAS_UNLOCK(la);
2622 }
2623
2624 void
LibAliasSetSkinnyPort(struct libalias * la,unsigned int port)2625 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2626 {
2627 LIBALIAS_LOCK(la);
2628 la->skinnyPort = port;
2629 LIBALIAS_UNLOCK(la);
2630 }
2631
2632 /*
2633 * Find the address to redirect incoming packets
2634 */
2635 struct in_addr
FindSctpRedirectAddress(struct libalias * la,struct sctp_nat_msg * sm)2636 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2637 {
2638 struct alias_link *lnk;
2639 struct in_addr redir;
2640
2641 LIBALIAS_LOCK_ASSERT(la);
2642 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2643 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2644 if (lnk != NULL) {
2645 /* port redirect */
2646 return (lnk->src_addr);
2647 } else {
2648 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2649 if (redir.s_addr == la->aliasAddress.s_addr ||
2650 redir.s_addr == la->targetAddress.s_addr) {
2651 /* No address found */
2652 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2653 NO_DEST_PORT, 0, LINK_SCTP, 1);
2654 if (lnk != NULL)
2655 /* redirect proto */
2656 return (lnk->src_addr);
2657 }
2658 return (redir); /* address redirect */
2659 }
2660 }
2661