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