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