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