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