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 struct alias_link *found; 873 874 found = UseLink(la, lnk); 875 if (found != NULL) 876 return (found); 877 /* link expired */ 878 break; 879 } 880 } 881 break; 882 case LINK_UNKNOWN_DEST_PORT: 883 LIST_FOREACH(lnk, &grp->full, all.in) { 884 if(lnk->dst_addr.s_addr == dst_addr.s_addr) { 885 lnk_unknown_dst_port = lnk; 886 break; 887 } 888 } 889 break; 890 case LINK_UNKNOWN_DEST_ADDR: 891 LIST_FOREACH(lnk, &grp->full, all.in) { 892 if(lnk->dst_port == dst_port) { 893 lnk_unknown_dst_addr = lnk; 894 break; 895 } 896 } 897 break; 898 case LINK_PARTIALLY_SPECIFIED: 899 lnk_unknown_all = LIST_FIRST(&grp->full); 900 break; 901 } 902 903 if (lnk_unknown_dst_port == NULL) { 904 LIST_FOREACH(lnk, &grp->partial, all.in) { 905 int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED; 906 907 if (flags == LINK_PARTIALLY_SPECIFIED && 908 lnk_unknown_all == NULL) 909 lnk_unknown_all = lnk; 910 if (flags == LINK_UNKNOWN_DEST_ADDR && 911 lnk->dst_port == dst_port && 912 lnk_unknown_dst_addr == NULL) 913 lnk_unknown_dst_addr = lnk; 914 if (flags == LINK_UNKNOWN_DEST_PORT && 915 lnk->dst_addr.s_addr == dst_addr.s_addr) { 916 lnk_unknown_dst_port = lnk; 917 break; 918 } 919 } 920 } 921 922 lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port 923 : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr 924 : lnk_unknown_all; 925 926 if (lnk == NULL || !replace_partial_links) 927 return (lnk); 928 929 if (lnk->server != NULL) { /* LSNAT link */ 930 src_addr = lnk->server->addr; 931 src_port = lnk->server->port; 932 lnk->server = lnk->server->next; 933 } else { 934 src_addr = lnk->src_addr; 935 src_port = lnk->src_port; 936 } 937 938 if (link_type == LINK_SCTP) { 939 lnk->src_addr = src_addr; 940 lnk->src_port = src_port; 941 } else { 942 lnk = ReLink(lnk, 943 src_addr, dst_addr, alias_addr, 944 src_port, dst_port, alias_port, 945 link_type, 0); 946 } 947 return (lnk); 948 } 949 950 static struct alias_link * 951 FindLinkIn(struct libalias *la, struct in_addr dst_addr, 952 struct in_addr alias_addr, 953 u_short dst_port, 954 u_short alias_port, 955 int link_type, 956 int replace_partial_links) 957 { 958 struct alias_link *lnk; 959 960 LIBALIAS_LOCK_ASSERT(la); 961 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 962 link_type, replace_partial_links); 963 964 if (lnk == NULL) { 965 /* 966 * The following allows permanent links to be specified as 967 * using the default aliasing address (i.e. device 968 * interface address) without knowing in advance what that 969 * address is. 970 */ 971 if (la->aliasAddress.s_addr != INADDR_ANY && 972 alias_addr.s_addr == la->aliasAddress.s_addr) { 973 lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port, 974 link_type, replace_partial_links); 975 } 976 } 977 return (lnk); 978 } 979 980 /* External routines for finding/adding links 981 982 -- "external" means outside alias_db.c, but within alias*.c -- 983 984 FindIcmpIn(), FindIcmpOut() 985 FindFragmentIn1(), FindFragmentIn2() 986 AddFragmentPtrLink(), FindFragmentPtr() 987 FindProtoIn(), FindProtoOut() 988 FindUdpTcpIn(), FindUdpTcpOut() 989 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 990 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 991 FindOriginalAddress(), FindAliasAddress() 992 993 (prototypes in alias_local.h) 994 */ 995 996 struct alias_link * 997 FindIcmpIn(struct libalias *la, struct in_addr dst_addr, 998 struct in_addr alias_addr, 999 u_short id_alias, 1000 int create) 1001 { 1002 struct alias_link *lnk; 1003 1004 LIBALIAS_LOCK_ASSERT(la); 1005 lnk = FindLinkIn(la, dst_addr, alias_addr, 1006 NO_DEST_PORT, id_alias, 1007 LINK_ICMP, 0); 1008 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1009 struct in_addr target_addr; 1010 1011 target_addr = FindOriginalAddress(la, alias_addr); 1012 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1013 id_alias, NO_DEST_PORT, id_alias, 1014 LINK_ICMP); 1015 } 1016 return (lnk); 1017 } 1018 1019 struct alias_link * 1020 FindIcmpOut(struct libalias *la, struct in_addr src_addr, 1021 struct in_addr dst_addr, 1022 u_short id, 1023 int create) 1024 { 1025 struct alias_link *lnk; 1026 1027 LIBALIAS_LOCK_ASSERT(la); 1028 lnk = FindLinkOut(la, src_addr, dst_addr, 1029 id, NO_DEST_PORT, 1030 LINK_ICMP, 0); 1031 if (lnk == NULL && create) { 1032 struct in_addr alias_addr; 1033 1034 alias_addr = FindAliasAddress(la, src_addr); 1035 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1036 id, NO_DEST_PORT, GET_ALIAS_ID, 1037 LINK_ICMP); 1038 } 1039 return (lnk); 1040 } 1041 1042 struct alias_link * 1043 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1044 struct in_addr alias_addr, 1045 u_short ip_id) 1046 { 1047 struct alias_link *lnk; 1048 1049 LIBALIAS_LOCK_ASSERT(la); 1050 lnk = FindLinkIn(la, dst_addr, alias_addr, 1051 NO_DEST_PORT, ip_id, 1052 LINK_FRAGMENT_ID, 0); 1053 1054 if (lnk == NULL) { 1055 lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr, 1056 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1057 LINK_FRAGMENT_ID); 1058 } 1059 return (lnk); 1060 } 1061 1062 /* Doesn't add a link if one is not found. */ 1063 struct alias_link * 1064 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, 1065 struct in_addr alias_addr, u_short ip_id) 1066 { 1067 LIBALIAS_LOCK_ASSERT(la); 1068 return FindLinkIn(la, dst_addr, alias_addr, 1069 NO_DEST_PORT, ip_id, 1070 LINK_FRAGMENT_ID, 0); 1071 } 1072 1073 struct alias_link * 1074 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1075 u_short ip_id) 1076 { 1077 LIBALIAS_LOCK_ASSERT(la); 1078 return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR, 1079 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1080 LINK_FRAGMENT_PTR); 1081 } 1082 1083 struct alias_link * 1084 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1085 u_short ip_id) 1086 { 1087 LIBALIAS_LOCK_ASSERT(la); 1088 return FindLinkIn(la, dst_addr, ANY_ADDR, 1089 NO_DEST_PORT, ip_id, 1090 LINK_FRAGMENT_PTR, 0); 1091 } 1092 1093 struct alias_link * 1094 FindProtoIn(struct libalias *la, struct in_addr dst_addr, 1095 struct in_addr alias_addr, 1096 u_char proto) 1097 { 1098 struct alias_link *lnk; 1099 1100 LIBALIAS_LOCK_ASSERT(la); 1101 lnk = FindLinkIn(la, dst_addr, alias_addr, 1102 NO_DEST_PORT, 0, 1103 proto, 1); 1104 1105 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1106 struct in_addr target_addr; 1107 1108 target_addr = FindOriginalAddress(la, alias_addr); 1109 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1110 NO_SRC_PORT, NO_DEST_PORT, 0, 1111 proto); 1112 } 1113 return (lnk); 1114 } 1115 1116 struct alias_link * 1117 FindProtoOut(struct libalias *la, struct in_addr src_addr, 1118 struct in_addr dst_addr, 1119 u_char proto) 1120 { 1121 struct alias_link *lnk; 1122 1123 LIBALIAS_LOCK_ASSERT(la); 1124 lnk = FindLinkOut(la, src_addr, dst_addr, 1125 NO_SRC_PORT, NO_DEST_PORT, 1126 proto, 1); 1127 1128 if (lnk == NULL) { 1129 struct in_addr alias_addr; 1130 1131 alias_addr = FindAliasAddress(la, src_addr); 1132 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1133 NO_SRC_PORT, NO_DEST_PORT, 0, 1134 proto); 1135 } 1136 return (lnk); 1137 } 1138 1139 struct alias_link * 1140 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1141 struct in_addr alias_addr, 1142 u_short dst_port, 1143 u_short alias_port, 1144 u_char proto, 1145 int create) 1146 { 1147 int link_type; 1148 struct alias_link *lnk; 1149 1150 LIBALIAS_LOCK_ASSERT(la); 1151 switch (proto) { 1152 case IPPROTO_UDP: 1153 link_type = LINK_UDP; 1154 break; 1155 case IPPROTO_TCP: 1156 link_type = LINK_TCP; 1157 break; 1158 default: 1159 return (NULL); 1160 break; 1161 } 1162 1163 lnk = FindLinkIn(la, dst_addr, alias_addr, 1164 dst_port, alias_port, 1165 link_type, create); 1166 1167 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1168 struct in_addr target_addr; 1169 1170 target_addr = FindOriginalAddress(la, alias_addr); 1171 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1172 alias_port, dst_port, alias_port, 1173 link_type); 1174 } 1175 return (lnk); 1176 } 1177 1178 struct alias_link * 1179 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1180 struct in_addr dst_addr, 1181 u_short src_port, 1182 u_short dst_port, 1183 u_char proto, 1184 int create) 1185 { 1186 int link_type; 1187 struct alias_link *lnk; 1188 1189 LIBALIAS_LOCK_ASSERT(la); 1190 switch (proto) { 1191 case IPPROTO_UDP: 1192 link_type = LINK_UDP; 1193 break; 1194 case IPPROTO_TCP: 1195 link_type = LINK_TCP; 1196 break; 1197 default: 1198 return (NULL); 1199 break; 1200 } 1201 1202 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1203 1204 if (lnk == NULL && create) { 1205 struct in_addr alias_addr; 1206 1207 alias_addr = FindAliasAddress(la, src_addr); 1208 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1209 src_port, dst_port, GET_ALIAS_PORT, 1210 link_type); 1211 } 1212 return (lnk); 1213 } 1214 1215 struct alias_link * 1216 AddPptp(struct libalias *la, struct in_addr src_addr, 1217 struct in_addr dst_addr, 1218 struct in_addr alias_addr, 1219 u_int16_t src_call_id) 1220 { 1221 struct alias_link *lnk; 1222 1223 LIBALIAS_LOCK_ASSERT(la); 1224 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1225 src_call_id, 0, GET_ALIAS_PORT, 1226 LINK_PPTP); 1227 1228 return (lnk); 1229 } 1230 1231 struct alias_link * 1232 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1233 struct in_addr dst_addr, 1234 u_int16_t src_call_id) 1235 { 1236 struct alias_link *lnk; 1237 1238 LIBALIAS_LOCK_ASSERT(la); 1239 LIST_FOREACH(lnk, &la->pptpList, pptp.list) 1240 if (lnk->src_addr.s_addr == src_addr.s_addr && 1241 lnk->dst_addr.s_addr == dst_addr.s_addr && 1242 lnk->src_port == src_call_id) 1243 break; 1244 1245 return (UseLink(la, lnk)); 1246 } 1247 1248 struct alias_link * 1249 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1250 struct in_addr dst_addr, 1251 u_int16_t dst_call_id) 1252 { 1253 struct alias_link *lnk; 1254 1255 LIBALIAS_LOCK_ASSERT(la); 1256 LIST_FOREACH(lnk, &la->pptpList, pptp.list) 1257 if (lnk->src_addr.s_addr == src_addr.s_addr && 1258 lnk->dst_addr.s_addr == dst_addr.s_addr && 1259 lnk->dst_port == dst_call_id) 1260 break; 1261 1262 return (UseLink(la, lnk)); 1263 } 1264 1265 struct alias_link * 1266 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1267 struct in_addr alias_addr, 1268 u_int16_t dst_call_id) 1269 { 1270 struct alias_link *lnk; 1271 1272 LIBALIAS_LOCK_ASSERT(la); 1273 1274 LIST_FOREACH(lnk, &la->pptpList, pptp.list) 1275 if (lnk->dst_port == dst_call_id && 1276 lnk->dst_addr.s_addr == dst_addr.s_addr && 1277 lnk->alias_addr.s_addr == alias_addr.s_addr) 1278 break; 1279 1280 return (UseLink(la, lnk)); 1281 } 1282 1283 struct alias_link * 1284 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1285 struct in_addr alias_addr, 1286 u_int16_t alias_call_id) 1287 { 1288 struct alias_link *lnk; 1289 1290 LIBALIAS_LOCK_ASSERT(la); 1291 LIST_FOREACH(lnk, &la->pptpList, pptp.list) 1292 if (lnk->alias_port == alias_call_id && 1293 lnk->dst_addr.s_addr == dst_addr.s_addr && 1294 lnk->alias_addr.s_addr == alias_addr.s_addr) 1295 break; 1296 1297 return (lnk); 1298 } 1299 1300 struct alias_link * 1301 FindRtspOut(struct libalias *la, struct in_addr src_addr, 1302 struct in_addr dst_addr, 1303 u_short src_port, 1304 u_short alias_port, 1305 u_char proto) 1306 { 1307 int link_type; 1308 struct alias_link *lnk; 1309 1310 LIBALIAS_LOCK_ASSERT(la); 1311 switch (proto) { 1312 case IPPROTO_UDP: 1313 link_type = LINK_UDP; 1314 break; 1315 case IPPROTO_TCP: 1316 link_type = LINK_TCP; 1317 break; 1318 default: 1319 return (NULL); 1320 break; 1321 } 1322 1323 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1324 1325 if (lnk == NULL) { 1326 struct in_addr alias_addr; 1327 1328 alias_addr = FindAliasAddress(la, src_addr); 1329 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1330 src_port, 0, alias_port, 1331 link_type); 1332 } 1333 return (lnk); 1334 } 1335 1336 struct in_addr 1337 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1338 { 1339 struct alias_link *lnk; 1340 1341 LIBALIAS_LOCK_ASSERT(la); 1342 lnk = FindLinkIn(la, ANY_ADDR, alias_addr, 1343 0, 0, LINK_ADDR, 0); 1344 if (lnk == NULL) { 1345 if (la->targetAddress.s_addr == INADDR_ANY) 1346 return (alias_addr); 1347 else if (la->targetAddress.s_addr == INADDR_NONE) 1348 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1349 la->aliasAddress : alias_addr; 1350 else 1351 return (la->targetAddress); 1352 } else { 1353 if (lnk->server != NULL) { /* LSNAT link */ 1354 struct in_addr src_addr; 1355 1356 src_addr = lnk->server->addr; 1357 lnk->server = lnk->server->next; 1358 return (src_addr); 1359 } else if (lnk->src_addr.s_addr == INADDR_ANY) 1360 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1361 la->aliasAddress : alias_addr; 1362 else 1363 return (lnk->src_addr); 1364 } 1365 } 1366 1367 struct in_addr 1368 FindAliasAddress(struct libalias *la, struct in_addr original_addr) 1369 { 1370 struct alias_link *lnk; 1371 1372 LIBALIAS_LOCK_ASSERT(la); 1373 lnk = FindLinkOut(la, original_addr, ANY_ADDR, 1374 0, 0, LINK_ADDR, 0); 1375 if (lnk == NULL) { 1376 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1377 la->aliasAddress : original_addr; 1378 } else { 1379 if (lnk->alias_addr.s_addr == INADDR_ANY) 1380 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1381 la->aliasAddress : original_addr; 1382 else 1383 return (lnk->alias_addr); 1384 } 1385 } 1386 1387 /* External routines for getting or changing link data 1388 (external to alias_db.c, but internal to alias*.c) 1389 1390 SetFragmentData(), GetFragmentData() 1391 SetFragmentPtr(), GetFragmentPtr() 1392 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1393 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1394 GetOriginalPort(), GetAliasPort() 1395 SetAckModified(), GetAckModified() 1396 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1397 SetProtocolFlags(), GetProtocolFlags() 1398 SetDestCallId() 1399 */ 1400 1401 void 1402 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1403 { 1404 lnk->data.frag_addr = src_addr; 1405 } 1406 1407 void 1408 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1409 { 1410 *src_addr = lnk->data.frag_addr; 1411 } 1412 1413 void 1414 SetFragmentPtr(struct alias_link *lnk, void *fptr) 1415 { 1416 lnk->data.frag_ptr = fptr; 1417 } 1418 1419 void 1420 GetFragmentPtr(struct alias_link *lnk, void **fptr) 1421 { 1422 *fptr = lnk->data.frag_ptr; 1423 } 1424 1425 void 1426 SetStateIn(struct alias_link *lnk, int state) 1427 { 1428 /* TCP input state */ 1429 switch (state) { 1430 case ALIAS_TCP_STATE_DISCONNECTED: 1431 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1432 lnk->expire.time = TCP_EXPIRE_DEAD; 1433 else 1434 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD; 1435 break; 1436 case ALIAS_TCP_STATE_CONNECTED: 1437 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1438 lnk->expire.time = TCP_EXPIRE_CONNECTED; 1439 break; 1440 default: 1441 #ifdef _KERNEL 1442 panic("libalias:SetStateIn() unknown state"); 1443 #else 1444 abort(); 1445 #endif 1446 } 1447 lnk->data.tcp->state.in = state; 1448 } 1449 1450 void 1451 SetStateOut(struct alias_link *lnk, int state) 1452 { 1453 /* TCP output state */ 1454 switch (state) { 1455 case ALIAS_TCP_STATE_DISCONNECTED: 1456 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1457 lnk->expire.time = TCP_EXPIRE_DEAD; 1458 else 1459 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD; 1460 break; 1461 case ALIAS_TCP_STATE_CONNECTED: 1462 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1463 lnk->expire.time = TCP_EXPIRE_CONNECTED; 1464 break; 1465 default: 1466 #ifdef _KERNEL 1467 panic("libalias:SetStateOut() unknown state"); 1468 #else 1469 abort(); 1470 #endif 1471 } 1472 lnk->data.tcp->state.out = state; 1473 } 1474 1475 int 1476 GetStateIn(struct alias_link *lnk) 1477 { 1478 /* TCP input state */ 1479 return (lnk->data.tcp->state.in); 1480 } 1481 1482 int 1483 GetStateOut(struct alias_link *lnk) 1484 { 1485 /* TCP output state */ 1486 return (lnk->data.tcp->state.out); 1487 } 1488 1489 struct in_addr 1490 GetOriginalAddress(struct alias_link *lnk) 1491 { 1492 if (lnk->src_addr.s_addr == INADDR_ANY) 1493 return (lnk->la->aliasAddress); 1494 else 1495 return (lnk->src_addr); 1496 } 1497 1498 struct in_addr 1499 GetDestAddress(struct alias_link *lnk) 1500 { 1501 return (lnk->dst_addr); 1502 } 1503 1504 struct in_addr 1505 GetAliasAddress(struct alias_link *lnk) 1506 { 1507 if (lnk->alias_addr.s_addr == INADDR_ANY) 1508 return (lnk->la->aliasAddress); 1509 else 1510 return (lnk->alias_addr); 1511 } 1512 1513 struct in_addr 1514 GetDefaultAliasAddress(struct libalias *la) 1515 { 1516 LIBALIAS_LOCK_ASSERT(la); 1517 return (la->aliasAddress); 1518 } 1519 1520 void 1521 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1522 { 1523 LIBALIAS_LOCK_ASSERT(la); 1524 la->aliasAddress = alias_addr; 1525 } 1526 1527 u_short 1528 GetOriginalPort(struct alias_link *lnk) 1529 { 1530 return (lnk->src_port); 1531 } 1532 1533 u_short 1534 GetAliasPort(struct alias_link *lnk) 1535 { 1536 return (lnk->alias_port); 1537 } 1538 1539 #ifndef NO_FW_PUNCH 1540 static u_short 1541 GetDestPort(struct alias_link *lnk) 1542 { 1543 return (lnk->dst_port); 1544 } 1545 1546 #endif 1547 1548 /* Indicate that ACK numbers have been modified in a TCP connection */ 1549 void 1550 SetAckModified(struct alias_link *lnk) 1551 { 1552 lnk->data.tcp->state.ack_modified = 1; 1553 } 1554 1555 struct in_addr 1556 GetProxyAddress(struct alias_link *lnk) 1557 { 1558 return (lnk->proxy_addr); 1559 } 1560 1561 void 1562 SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1563 { 1564 lnk->proxy_addr = addr; 1565 } 1566 1567 u_short 1568 GetProxyPort(struct alias_link *lnk) 1569 { 1570 return (lnk->proxy_port); 1571 } 1572 1573 void 1574 SetProxyPort(struct alias_link *lnk, u_short port) 1575 { 1576 lnk->proxy_port = port; 1577 } 1578 1579 /* See if ACK numbers have been modified */ 1580 int 1581 GetAckModified(struct alias_link *lnk) 1582 { 1583 return (lnk->data.tcp->state.ack_modified); 1584 } 1585 1586 /* 1587 * Find out how much the ACK number has been altered for an 1588 * incoming TCP packet. To do this, a circular list of ACK 1589 * numbers where the TCP packet size was altered is searched. 1590 */ 1591 // XXX ip free 1592 int 1593 GetDeltaAckIn(u_long ack, struct alias_link *lnk) 1594 { 1595 int i, j; 1596 int delta, ack_diff_min; 1597 1598 delta = 0; 1599 ack_diff_min = -1; 1600 i = lnk->data.tcp->state.index; 1601 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1602 struct ack_data_record x; 1603 1604 if (i == 0) 1605 i = N_LINK_TCP_DATA; 1606 i--; 1607 x = lnk->data.tcp->ack[i]; 1608 if (x.active == 1) { 1609 int ack_diff; 1610 1611 ack_diff = SeqDiff(x.ack_new, ack); 1612 if (ack_diff >= 0) { 1613 if (ack_diff_min >= 0) { 1614 if (ack_diff < ack_diff_min) { 1615 delta = x.delta; 1616 ack_diff_min = ack_diff; 1617 } 1618 } else { 1619 delta = x.delta; 1620 ack_diff_min = ack_diff; 1621 } 1622 } 1623 } 1624 } 1625 return (delta); 1626 } 1627 1628 /* 1629 * Find out how much the sequence number has been altered for an 1630 * outgoing TCP packet. To do this, a circular list of ACK numbers 1631 * where the TCP packet size was altered is searched. 1632 */ 1633 // XXX ip free 1634 int 1635 GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 1636 { 1637 int i, j; 1638 int delta, seq_diff_min; 1639 1640 delta = 0; 1641 seq_diff_min = -1; 1642 i = lnk->data.tcp->state.index; 1643 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1644 struct ack_data_record x; 1645 1646 if (i == 0) 1647 i = N_LINK_TCP_DATA; 1648 i--; 1649 x = lnk->data.tcp->ack[i]; 1650 if (x.active == 1) { 1651 int seq_diff; 1652 1653 seq_diff = SeqDiff(x.ack_old, seq); 1654 if (seq_diff >= 0) { 1655 if (seq_diff_min >= 0) { 1656 if (seq_diff < seq_diff_min) { 1657 delta = x.delta; 1658 seq_diff_min = seq_diff; 1659 } 1660 } else { 1661 delta = x.delta; 1662 seq_diff_min = seq_diff; 1663 } 1664 } 1665 } 1666 } 1667 return (delta); 1668 } 1669 1670 /* 1671 * When a TCP packet has been altered in length, save this 1672 * information in a circular list. If enough packets have been 1673 * altered, then this list will begin to overwrite itself. 1674 */ 1675 // XXX ip free 1676 void 1677 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 1678 u_long th_seq, u_int th_off) 1679 { 1680 struct ack_data_record x; 1681 int hlen, tlen, dlen; 1682 int i; 1683 1684 hlen = (ip_hl + th_off) << 2; 1685 tlen = ntohs(ip_len); 1686 dlen = tlen - hlen; 1687 1688 x.ack_old = htonl(ntohl(th_seq) + dlen); 1689 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 1690 x.delta = delta; 1691 x.active = 1; 1692 1693 i = lnk->data.tcp->state.index; 1694 lnk->data.tcp->ack[i] = x; 1695 1696 i++; 1697 if (i == N_LINK_TCP_DATA) 1698 lnk->data.tcp->state.index = 0; 1699 else 1700 lnk->data.tcp->state.index = i; 1701 } 1702 1703 void 1704 SetExpire(struct alias_link *lnk, int expire) 1705 { 1706 if (expire == 0) { 1707 lnk->flags &= ~LINK_PERMANENT; 1708 DeleteLink(&lnk, 0); 1709 } else if (expire == -1) { 1710 lnk->flags |= LINK_PERMANENT; 1711 } else if (expire > 0) { 1712 lnk->expire.time = expire; 1713 } else { 1714 #ifdef LIBALIAS_DEBUG 1715 fprintf(stderr, "PacketAlias/SetExpire(): "); 1716 fprintf(stderr, "error in expire parameter\n"); 1717 #endif 1718 } 1719 } 1720 1721 void 1722 SetProtocolFlags(struct alias_link *lnk, int pflags) 1723 { 1724 lnk->pflags = pflags; 1725 } 1726 1727 int 1728 GetProtocolFlags(struct alias_link *lnk) 1729 { 1730 return (lnk->pflags); 1731 } 1732 1733 void 1734 SetDestCallId(struct alias_link *lnk, u_int16_t cid) 1735 { 1736 LIBALIAS_LOCK_ASSERT(lnk->la); 1737 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 1738 lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1); 1739 } 1740 1741 /* Miscellaneous Functions 1742 1743 HouseKeeping() 1744 InitPacketAliasLog() 1745 UninitPacketAliasLog() 1746 */ 1747 1748 /* 1749 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1750 is called to find and remove timed-out aliasing links. Logic exists 1751 to sweep through the entire table and linked list structure 1752 every 60 seconds. 1753 1754 (prototype in alias_local.h) 1755 */ 1756 1757 void 1758 HouseKeeping(struct libalias *la) 1759 { 1760 static unsigned int packets = 0; 1761 static unsigned int packet_limit = 1000; 1762 1763 LIBALIAS_LOCK_ASSERT(la); 1764 packets++; 1765 1766 /* 1767 * User space time/gettimeofday/... is very expensive. 1768 * Kernel space cache trashing is unnecessary. 1769 * 1770 * Save system time (seconds) in global variable LibAliasTime 1771 * for use by other functions. This is done so as not to 1772 * unnecessarily waste timeline by making system calls. 1773 * 1774 * Reduce the amount of house keeping work substantially by 1775 * sampling over the packets. 1776 */ 1777 if (packet_limit <= 1 || packets % packet_limit == 0) { 1778 time_t now; 1779 1780 #ifdef _KERNEL 1781 now = time_uptime; 1782 #else 1783 now = time(NULL); 1784 #endif 1785 if (now != LibAliasTime) { 1786 /* retry three times a second */ 1787 packet_limit = packets / 3; 1788 packets = 0; 1789 LibAliasTime = now; 1790 } 1791 1792 } 1793 /* Do a cleanup for the first packets of the new second only */ 1794 if (packets < (la->udpLinkCount + la->tcpLinkCount)) { 1795 struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire); 1796 1797 CleanupLink(la, &lnk, 0); 1798 } 1799 } 1800 1801 /* Init the log file and enable logging */ 1802 static int 1803 InitPacketAliasLog(struct libalias *la) 1804 { 1805 LIBALIAS_LOCK_ASSERT(la); 1806 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 1807 #ifdef _KERNEL 1808 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 1809 ; 1810 #else 1811 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 1812 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1813 #endif 1814 else 1815 return (ENOMEM); /* log initialization failed */ 1816 la->packetAliasMode |= PKT_ALIAS_LOG; 1817 } 1818 1819 return (1); 1820 } 1821 1822 /* Close the log-file and disable logging. */ 1823 static void 1824 UninitPacketAliasLog(struct libalias *la) 1825 { 1826 LIBALIAS_LOCK_ASSERT(la); 1827 if (la->logDesc) { 1828 #ifdef _KERNEL 1829 free(la->logDesc); 1830 #else 1831 fclose(la->logDesc); 1832 #endif 1833 la->logDesc = NULL; 1834 } 1835 la->packetAliasMode &= ~PKT_ALIAS_LOG; 1836 } 1837 1838 /* Outside world interfaces 1839 1840 -- "outside world" means other than alias*.c routines -- 1841 1842 PacketAliasRedirectPort() 1843 PacketAliasAddServer() 1844 PacketAliasRedirectProto() 1845 PacketAliasRedirectAddr() 1846 PacketAliasRedirectDynamic() 1847 PacketAliasRedirectDelete() 1848 PacketAliasSetAddress() 1849 PacketAliasInit() 1850 PacketAliasUninit() 1851 PacketAliasSetMode() 1852 1853 (prototypes in alias.h) 1854 */ 1855 1856 /* Redirection from a specific public addr:port to a 1857 private addr:port */ 1858 struct alias_link * 1859 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 1860 struct in_addr dst_addr, u_short dst_port, 1861 struct in_addr alias_addr, u_short alias_port, 1862 u_char proto) 1863 { 1864 int link_type; 1865 struct alias_link *lnk; 1866 1867 LIBALIAS_LOCK(la); 1868 switch (proto) { 1869 case IPPROTO_UDP: 1870 link_type = LINK_UDP; 1871 break; 1872 case IPPROTO_TCP: 1873 link_type = LINK_TCP; 1874 break; 1875 case IPPROTO_SCTP: 1876 link_type = LINK_SCTP; 1877 break; 1878 default: 1879 #ifdef LIBALIAS_DEBUG 1880 fprintf(stderr, "PacketAliasRedirectPort(): "); 1881 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 1882 #endif 1883 lnk = NULL; 1884 goto getout; 1885 } 1886 1887 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1888 src_port, dst_port, alias_port, 1889 link_type); 1890 1891 if (lnk != NULL) { 1892 lnk->flags |= LINK_PERMANENT; 1893 } 1894 #ifdef LIBALIAS_DEBUG 1895 else { 1896 fprintf(stderr, "PacketAliasRedirectPort(): " 1897 "call to AddLink() failed\n"); 1898 } 1899 #endif 1900 1901 getout: 1902 LIBALIAS_UNLOCK(la); 1903 return (lnk); 1904 } 1905 1906 /* Add server to the pool of servers */ 1907 int 1908 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 1909 { 1910 struct server *server; 1911 int res; 1912 1913 LIBALIAS_LOCK(la); 1914 (void)la; 1915 1916 switch (lnk->link_type) { 1917 case LINK_PPTP: 1918 server = NULL; 1919 break; 1920 default: 1921 server = malloc(sizeof(struct server)); 1922 break; 1923 } 1924 1925 if (server != NULL) { 1926 struct server *head; 1927 1928 server->addr = addr; 1929 server->port = port; 1930 1931 head = lnk->server; 1932 if (head == NULL) { 1933 server->next = server; 1934 /* not usable for outgoing connections */ 1935 SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk); 1936 } else { 1937 struct server *s; 1938 1939 for (s = head; s->next != head; s = s->next) 1940 ; 1941 s->next = server; 1942 server->next = head; 1943 } 1944 lnk->server = server; 1945 res = 0; 1946 } else 1947 res = -1; 1948 1949 LIBALIAS_UNLOCK(la); 1950 return (res); 1951 } 1952 1953 /* Redirect packets of a given IP protocol from a specific 1954 public address to a private address */ 1955 struct alias_link * 1956 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 1957 struct in_addr dst_addr, 1958 struct in_addr alias_addr, 1959 u_char proto) 1960 { 1961 struct alias_link *lnk; 1962 1963 LIBALIAS_LOCK(la); 1964 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1965 NO_SRC_PORT, NO_DEST_PORT, 0, 1966 proto); 1967 1968 if (lnk != NULL) { 1969 lnk->flags |= LINK_PERMANENT; 1970 } 1971 #ifdef LIBALIAS_DEBUG 1972 else { 1973 fprintf(stderr, "PacketAliasRedirectProto(): " 1974 "call to AddLink() failed\n"); 1975 } 1976 #endif 1977 1978 LIBALIAS_UNLOCK(la); 1979 return (lnk); 1980 } 1981 1982 /* Static address translation */ 1983 struct alias_link * 1984 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 1985 struct in_addr alias_addr) 1986 { 1987 struct alias_link *lnk; 1988 1989 LIBALIAS_LOCK(la); 1990 lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr, 1991 0, 0, 0, 1992 LINK_ADDR); 1993 1994 if (lnk != NULL) { 1995 lnk->flags |= LINK_PERMANENT; 1996 } 1997 #ifdef LIBALIAS_DEBUG 1998 else { 1999 fprintf(stderr, "PacketAliasRedirectAddr(): " 2000 "call to AddLink() failed\n"); 2001 } 2002 #endif 2003 2004 LIBALIAS_UNLOCK(la); 2005 return (lnk); 2006 } 2007 2008 /* Mark the aliasing link dynamic */ 2009 int 2010 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2011 { 2012 int res; 2013 2014 LIBALIAS_LOCK(la); 2015 (void)la; 2016 2017 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2018 res = -1; 2019 else { 2020 lnk->flags &= ~LINK_PERMANENT; 2021 res = 0; 2022 } 2023 LIBALIAS_UNLOCK(la); 2024 return (res); 2025 } 2026 2027 /* This is a dangerous function to put in the API, 2028 because an invalid pointer can crash the program. */ 2029 void 2030 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2031 { 2032 LIBALIAS_LOCK(la); 2033 (void)la; 2034 DeleteLink(&lnk, 1); 2035 LIBALIAS_UNLOCK(la); 2036 } 2037 2038 void 2039 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2040 { 2041 LIBALIAS_LOCK(la); 2042 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2043 && la->aliasAddress.s_addr != addr.s_addr) 2044 CleanupAliasData(la, 0); 2045 2046 la->aliasAddress = addr; 2047 LIBALIAS_UNLOCK(la); 2048 } 2049 2050 void 2051 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, 2052 u_short port_high) 2053 { 2054 LIBALIAS_LOCK(la); 2055 if (port_low) { 2056 la->aliasPortLower = port_low; 2057 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ 2058 la->aliasPortLength = port_high - port_low + 1; 2059 } else { 2060 /* Set default values */ 2061 la->aliasPortLower = 0x8000; 2062 la->aliasPortLength = 0x8000; 2063 } 2064 LIBALIAS_UNLOCK(la); 2065 } 2066 2067 void 2068 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2069 { 2070 LIBALIAS_LOCK(la); 2071 la->targetAddress = target_addr; 2072 LIBALIAS_UNLOCK(la); 2073 } 2074 2075 static void 2076 finishoff(void) 2077 { 2078 while (!LIST_EMPTY(&instancehead)) 2079 LibAliasUninit(LIST_FIRST(&instancehead)); 2080 } 2081 2082 struct libalias * 2083 LibAliasInit(struct libalias *la) 2084 { 2085 if (la == NULL) { 2086 #ifdef _KERNEL 2087 #undef malloc /* XXX: ugly */ 2088 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO); 2089 #else 2090 la = calloc(sizeof *la, 1); 2091 if (la == NULL) 2092 return (la); 2093 #endif 2094 2095 #ifndef _KERNEL 2096 /* kernel cleans up on module unload */ 2097 if (LIST_EMPTY(&instancehead)) 2098 atexit(finishoff); 2099 #endif 2100 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2101 2102 #ifdef _KERNEL 2103 LibAliasTime = time_uptime; 2104 #else 2105 LibAliasTime = time(NULL); 2106 #endif 2107 2108 SPLAY_INIT(&la->linkSplayIn); 2109 SPLAY_INIT(&la->linkSplayOut); 2110 LIST_INIT(&la->pptpList); 2111 TAILQ_INIT(&la->checkExpire); 2112 #ifdef _KERNEL 2113 AliasSctpInit(la); 2114 #endif 2115 LIBALIAS_LOCK_INIT(la); 2116 LIBALIAS_LOCK(la); 2117 } else { 2118 LIBALIAS_LOCK(la); 2119 CleanupAliasData(la, 1); 2120 #ifdef _KERNEL 2121 AliasSctpTerm(la); 2122 AliasSctpInit(la); 2123 #endif 2124 } 2125 2126 la->aliasAddress.s_addr = INADDR_ANY; 2127 la->targetAddress.s_addr = INADDR_ANY; 2128 la->aliasPortLower = 0x8000; 2129 la->aliasPortLength = 0x8000; 2130 2131 la->icmpLinkCount = 0; 2132 la->udpLinkCount = 0; 2133 la->tcpLinkCount = 0; 2134 la->sctpLinkCount = 0; 2135 la->pptpLinkCount = 0; 2136 la->protoLinkCount = 0; 2137 la->fragmentIdLinkCount = 0; 2138 la->fragmentPtrLinkCount = 0; 2139 la->sockCount = 0; 2140 2141 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2142 #ifndef NO_USE_SOCKETS 2143 | PKT_ALIAS_USE_SOCKETS 2144 #endif 2145 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2146 #ifndef NO_FW_PUNCH 2147 la->fireWallFD = -1; 2148 #endif 2149 #ifndef _KERNEL 2150 LibAliasRefreshModules(); 2151 #endif 2152 LIBALIAS_UNLOCK(la); 2153 return (la); 2154 } 2155 2156 void 2157 LibAliasUninit(struct libalias *la) 2158 { 2159 LIBALIAS_LOCK(la); 2160 #ifdef _KERNEL 2161 AliasSctpTerm(la); 2162 #endif 2163 CleanupAliasData(la, 1); 2164 UninitPacketAliasLog(la); 2165 #ifndef NO_FW_PUNCH 2166 UninitPunchFW(la); 2167 #endif 2168 LIST_REMOVE(la, instancelist); 2169 LIBALIAS_UNLOCK(la); 2170 LIBALIAS_LOCK_DESTROY(la); 2171 free(la); 2172 } 2173 2174 /* Change mode for some operations */ 2175 unsigned int 2176 LibAliasSetMode( 2177 struct libalias *la, 2178 unsigned int flags, /* Which state to bring flags to */ 2179 unsigned int mask /* Mask of which flags to affect (use 0 to 2180 * do a probe for flag values) */ 2181 ) 2182 { 2183 int res = -1; 2184 2185 LIBALIAS_LOCK(la); 2186 if (flags & mask & PKT_ALIAS_LOG) { 2187 /* Enable logging */ 2188 if (InitPacketAliasLog(la) == ENOMEM) 2189 goto getout; 2190 } else if (~flags & mask & PKT_ALIAS_LOG) 2191 /* _Disable_ logging */ 2192 UninitPacketAliasLog(la); 2193 2194 #ifndef NO_FW_PUNCH 2195 if (flags & mask & PKT_ALIAS_PUNCH_FW) 2196 /* Start punching holes in the firewall? */ 2197 InitPunchFW(la); 2198 else if (~flags & mask & PKT_ALIAS_PUNCH_FW) 2199 /* Stop punching holes in the firewall? */ 2200 UninitPunchFW(la); 2201 #endif 2202 2203 /* Other flags can be set/cleared without special action */ 2204 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2205 res = la->packetAliasMode; 2206 getout: 2207 LIBALIAS_UNLOCK(la); 2208 return (res); 2209 } 2210 2211 #ifndef NO_FW_PUNCH 2212 2213 /***************** 2214 Code to support firewall punching. This shouldn't really be in this 2215 file, but making variables global is evil too. 2216 ****************/ 2217 2218 /* Firewall include files */ 2219 #include <net/if.h> 2220 #include <netinet/ip_fw.h> 2221 #include <string.h> 2222 #include <err.h> 2223 2224 /* 2225 * helper function, updates the pointer to cmd with the length 2226 * of the current command, and also cleans up the first word of 2227 * the new command in case it has been clobbered before. 2228 */ 2229 static ipfw_insn * 2230 next_cmd(ipfw_insn * cmd) 2231 { 2232 cmd += F_LEN(cmd); 2233 bzero(cmd, sizeof(*cmd)); 2234 return (cmd); 2235 } 2236 2237 /* 2238 * A function to fill simple commands of size 1. 2239 * Existing flags are preserved. 2240 */ 2241 static ipfw_insn * 2242 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2243 int flags, u_int16_t arg) 2244 { 2245 cmd->opcode = opcode; 2246 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2247 cmd->arg1 = arg; 2248 return next_cmd(cmd); 2249 } 2250 2251 static ipfw_insn * 2252 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2253 { 2254 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2255 2256 cmd->addr.s_addr = addr; 2257 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2258 } 2259 2260 static ipfw_insn * 2261 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2262 { 2263 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2264 2265 cmd->ports[0] = cmd->ports[1] = port; 2266 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2267 } 2268 2269 static int 2270 fill_rule(void *buf, int bufsize, int rulenum, 2271 enum ipfw_opcodes action, int proto, 2272 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2273 { 2274 struct ip_fw *rule = (struct ip_fw *)buf; 2275 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2276 2277 bzero(buf, bufsize); 2278 rule->rulenum = rulenum; 2279 2280 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2281 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2282 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2283 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2284 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2285 2286 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2287 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2288 2289 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2290 2291 return ((char *)cmd - (char *)buf); 2292 } 2293 2294 static void 2295 InitPunchFW(struct libalias *la) 2296 { 2297 la->fireWallField = malloc(la->fireWallNumNums); 2298 if (la->fireWallField) { 2299 memset(la->fireWallField, 0, la->fireWallNumNums); 2300 if (la->fireWallFD < 0) { 2301 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2302 } 2303 ClearAllFWHoles(la); 2304 la->fireWallActiveNum = la->fireWallBaseNum; 2305 } 2306 } 2307 2308 static void 2309 UninitPunchFW(struct libalias *la) 2310 { 2311 ClearAllFWHoles(la); 2312 if (la->fireWallFD >= 0) 2313 close(la->fireWallFD); 2314 la->fireWallFD = -1; 2315 if (la->fireWallField) 2316 free(la->fireWallField); 2317 la->fireWallField = NULL; 2318 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2319 } 2320 2321 /* Make a certain link go through the firewall */ 2322 void 2323 PunchFWHole(struct alias_link *lnk) 2324 { 2325 struct libalias *la; 2326 int r; /* Result code */ 2327 struct ip_fw rule; /* On-the-fly built rule */ 2328 int fwhole; /* Where to punch hole */ 2329 2330 la = lnk->la; 2331 2332 /* Don't do anything unless we are asked to */ 2333 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2334 la->fireWallFD < 0 || 2335 lnk->link_type != LINK_TCP) 2336 return; 2337 2338 memset(&rule, 0, sizeof rule); 2339 2340 /** Build rule **/ 2341 2342 /* Find empty slot */ 2343 for (fwhole = la->fireWallActiveNum; 2344 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2345 fw_tstfield(la, la->fireWallField, fwhole); 2346 fwhole++); 2347 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2348 for (fwhole = la->fireWallBaseNum; 2349 fwhole < la->fireWallActiveNum && 2350 fw_tstfield(la, la->fireWallField, fwhole); 2351 fwhole++); 2352 if (fwhole == la->fireWallActiveNum) { 2353 /* No rule point empty - we can't punch more holes. */ 2354 la->fireWallActiveNum = la->fireWallBaseNum; 2355 #ifdef LIBALIAS_DEBUG 2356 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2357 #endif 2358 return; 2359 } 2360 } 2361 /* Start next search at next position */ 2362 la->fireWallActiveNum = fwhole + 1; 2363 2364 /* 2365 * generate two rules of the form 2366 * 2367 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2368 * accept tcp from DAddr DPort to OAddr OPort 2369 */ 2370 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2371 u_int32_t rulebuf[255]; 2372 int i; 2373 2374 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2375 O_ACCEPT, IPPROTO_TCP, 2376 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2377 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2378 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2379 if (r) 2380 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2381 2382 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2383 O_ACCEPT, IPPROTO_TCP, 2384 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2385 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2386 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2387 if (r) 2388 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2389 } 2390 2391 /* Indicate hole applied */ 2392 lnk->data.tcp->fwhole = fwhole; 2393 fw_setfield(la, la->fireWallField, fwhole); 2394 } 2395 2396 /* Remove a hole in a firewall associated with a particular alias 2397 lnk. Calling this too often is harmless. */ 2398 static void 2399 ClearFWHole(struct alias_link *lnk) 2400 { 2401 struct libalias *la; 2402 2403 la = lnk->la; 2404 if (lnk->link_type == LINK_TCP) { 2405 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */ 2406 struct ip_fw rule; 2407 2408 if (fwhole < 0) 2409 return; 2410 2411 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2412 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2413 &fwhole, sizeof fwhole)); 2414 fw_clrfield(la, la->fireWallField, fwhole); 2415 lnk->data.tcp->fwhole = -1; 2416 } 2417 } 2418 2419 /* Clear out the entire range dedicated to firewall holes. */ 2420 static void 2421 ClearAllFWHoles(struct libalias *la) 2422 { 2423 struct ip_fw rule; /* On-the-fly built rule */ 2424 int i; 2425 2426 if (la->fireWallFD < 0) 2427 return; 2428 2429 memset(&rule, 0, sizeof rule); 2430 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2431 int r = i; 2432 2433 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2434 } 2435 /* XXX: third arg correct here ? /phk */ 2436 memset(la->fireWallField, 0, la->fireWallNumNums); 2437 } 2438 2439 #endif /* !NO_FW_PUNCH */ 2440 2441 void 2442 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2443 { 2444 LIBALIAS_LOCK(la); 2445 #ifndef NO_FW_PUNCH 2446 la->fireWallBaseNum = base; 2447 la->fireWallNumNums = num; 2448 #endif 2449 LIBALIAS_UNLOCK(la); 2450 } 2451 2452 void 2453 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2454 { 2455 LIBALIAS_LOCK(la); 2456 la->skinnyPort = port; 2457 LIBALIAS_UNLOCK(la); 2458 } 2459 2460 /* 2461 * Find the address to redirect incoming packets 2462 */ 2463 struct in_addr 2464 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2465 { 2466 struct alias_link *lnk; 2467 struct in_addr redir; 2468 2469 LIBALIAS_LOCK_ASSERT(la); 2470 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2471 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2472 if (lnk != NULL) { 2473 /* port redirect */ 2474 return (lnk->src_addr); 2475 } else { 2476 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2477 if (redir.s_addr == la->aliasAddress.s_addr || 2478 redir.s_addr == la->targetAddress.s_addr) { 2479 /* No address found */ 2480 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2481 NO_DEST_PORT, 0, LINK_SCTP, 1); 2482 if (lnk != NULL) 2483 /* redirect proto */ 2484 return (lnk->src_addr); 2485 } 2486 return (redir); /* address redirect */ 2487 } 2488 } 2489