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