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