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