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