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