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