1 /*- 2 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* file: alias_proxy.c 31 32 This file encapsulates special operations related to transparent 33 proxy redirection. This is where packets with a particular destination, 34 usually tcp port 80, are redirected to a proxy server. 35 36 When packets are proxied, the destination address and port are 37 modified. In certain cases, it is necessary to somehow encode 38 the original address/port info into the packet. Two methods are 39 presently supported: addition of a [DEST addr port] string at the 40 beginning of a tcp stream, or inclusion of an optional field 41 in the IP header. 42 43 There is one public API function: 44 45 PacketAliasProxyRule() -- Adds and deletes proxy 46 rules. 47 48 Rules are stored in a linear linked list, so lookup efficiency 49 won't be too good for large lists. 50 51 52 Initial development: April, 1998 (cjm) 53 */ 54 55 56 /* System includes */ 57 #ifdef _KERNEL 58 #include <sys/param.h> 59 #include <sys/ctype.h> 60 #include <sys/libkern.h> 61 #include <sys/limits.h> 62 #else 63 #include <sys/types.h> 64 #include <ctype.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <netdb.h> 68 #include <string.h> 69 #endif 70 71 #include <netinet/tcp.h> 72 73 #ifdef _KERNEL 74 #include <netinet/libalias/alias.h> 75 #include <netinet/libalias/alias_local.h> 76 #include <netinet/libalias/alias_mod.h> 77 #else 78 #include <arpa/inet.h> 79 #include "alias.h" /* Public API functions for libalias */ 80 #include "alias_local.h" /* Functions used by alias*.c */ 81 #endif 82 83 /* 84 Data structures 85 */ 86 87 /* 88 * A linked list of arbitrary length, based on struct proxy_entry is 89 * used to store proxy rules. 90 */ 91 struct proxy_entry { 92 struct libalias *la; 93 #define PROXY_TYPE_ENCODE_NONE 1 94 #define PROXY_TYPE_ENCODE_TCPSTREAM 2 95 #define PROXY_TYPE_ENCODE_IPHDR 3 96 int rule_index; 97 int proxy_type; 98 u_char proto; 99 u_short proxy_port; 100 u_short server_port; 101 102 struct in_addr server_addr; 103 104 struct in_addr src_addr; 105 struct in_addr src_mask; 106 107 struct in_addr dst_addr; 108 struct in_addr dst_mask; 109 110 struct proxy_entry *next; 111 struct proxy_entry *last; 112 }; 113 114 115 116 /* 117 File scope variables 118 */ 119 120 121 122 /* Local (static) functions: 123 124 IpMask() -- Utility function for creating IP 125 masks from integer (1-32) specification. 126 IpAddr() -- Utility function for converting string 127 to IP address 128 IpPort() -- Utility function for converting string 129 to port number 130 RuleAdd() -- Adds an element to the rule list. 131 RuleDelete() -- Removes an element from the rule list. 132 RuleNumberDelete() -- Removes all elements from the rule list 133 having a certain rule number. 134 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 135 of a TCP stream. 136 ProxyEncodeIpHeader() -- Adds an IP option indicating the true 137 destination of a proxied IP packet 138 */ 139 140 static int IpMask(int, struct in_addr *); 141 static int IpAddr(char *, struct in_addr *); 142 static int IpPort(char *, int, int *); 143 static void RuleAdd(struct libalias *la, struct proxy_entry *); 144 static void RuleDelete(struct proxy_entry *); 145 static int RuleNumberDelete(struct libalias *la, int); 146 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 147 static void ProxyEncodeIpHeader(struct ip *, int); 148 149 static int 150 IpMask(int nbits, struct in_addr *mask) 151 { 152 int i; 153 u_int imask; 154 155 if (nbits < 0 || nbits > 32) 156 return (-1); 157 158 imask = 0; 159 for (i = 0; i < nbits; i++) 160 imask = (imask >> 1) + 0x80000000; 161 mask->s_addr = htonl(imask); 162 163 return (0); 164 } 165 166 static int 167 IpAddr(char *s, struct in_addr *addr) 168 { 169 if (inet_aton(s, addr) == 0) 170 return (-1); 171 else 172 return (0); 173 } 174 175 static int 176 IpPort(char *s, int proto, int *port) 177 { 178 int n; 179 180 n = sscanf(s, "%d", port); 181 if (n != 1) 182 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */ 183 { 184 struct servent *se; 185 186 if (proto == IPPROTO_TCP) 187 se = getservbyname(s, "tcp"); 188 else if (proto == IPPROTO_UDP) 189 se = getservbyname(s, "udp"); 190 else 191 return (-1); 192 193 if (se == NULL) 194 return (-1); 195 196 *port = (u_int) ntohs(se->s_port); 197 } 198 #else 199 return (-1); 200 #endif 201 return (0); 202 } 203 204 void 205 RuleAdd(struct libalias *la, struct proxy_entry *entry) 206 { 207 int rule_index; 208 struct proxy_entry *ptr; 209 struct proxy_entry *ptr_last; 210 211 LIBALIAS_LOCK_ASSERT(la); 212 213 entry->la = la; 214 if (la->proxyList == NULL) { 215 la->proxyList = entry; 216 entry->last = NULL; 217 entry->next = NULL; 218 return; 219 } 220 221 rule_index = entry->rule_index; 222 ptr = la->proxyList; 223 ptr_last = NULL; 224 while (ptr != NULL) { 225 if (ptr->rule_index >= rule_index) { 226 if (ptr_last == NULL) { 227 entry->next = la->proxyList; 228 entry->last = NULL; 229 la->proxyList->last = entry; 230 la->proxyList = entry; 231 return; 232 } 233 ptr_last->next = entry; 234 ptr->last = entry; 235 entry->last = ptr->last; 236 entry->next = ptr; 237 return; 238 } 239 ptr_last = ptr; 240 ptr = ptr->next; 241 } 242 243 ptr_last->next = entry; 244 entry->last = ptr_last; 245 entry->next = NULL; 246 } 247 248 static void 249 RuleDelete(struct proxy_entry *entry) 250 { 251 struct libalias *la; 252 253 la = entry->la; 254 LIBALIAS_LOCK_ASSERT(la); 255 if (entry->last != NULL) 256 entry->last->next = entry->next; 257 else 258 la->proxyList = entry->next; 259 260 if (entry->next != NULL) 261 entry->next->last = entry->last; 262 263 free(entry); 264 } 265 266 static int 267 RuleNumberDelete(struct libalias *la, int rule_index) 268 { 269 int err; 270 struct proxy_entry *ptr; 271 272 LIBALIAS_LOCK_ASSERT(la); 273 err = -1; 274 ptr = la->proxyList; 275 while (ptr != NULL) { 276 struct proxy_entry *ptr_next; 277 278 ptr_next = ptr->next; 279 if (ptr->rule_index == rule_index) { 280 err = 0; 281 RuleDelete(ptr); 282 } 283 ptr = ptr_next; 284 } 285 286 return (err); 287 } 288 289 static void 290 ProxyEncodeTcpStream(struct alias_link *lnk, 291 struct ip *pip, 292 int maxpacketsize) 293 { 294 int slen; 295 char buffer[40]; 296 struct tcphdr *tc; 297 298 /* Compute pointer to tcp header */ 299 tc = (struct tcphdr *)ip_next(pip); 300 301 /* Don't modify if once already modified */ 302 303 if (GetAckModified(lnk)) 304 return; 305 306 /* Translate destination address and port to string form */ 307 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 308 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 309 310 /* Pad string out to a multiple of two in length */ 311 slen = strlen(buffer); 312 switch (slen % 2) { 313 case 0: 314 strcat(buffer, " \n"); 315 slen += 2; 316 break; 317 case 1: 318 strcat(buffer, "\n"); 319 slen += 1; 320 } 321 322 /* Check for packet overflow */ 323 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 324 return; 325 326 /* Shift existing TCP data and insert destination string */ 327 { 328 int dlen; 329 int hlen; 330 char *p; 331 332 hlen = (pip->ip_hl + tc->th_off) << 2; 333 dlen = ntohs(pip->ip_len) - hlen; 334 335 /* Modify first packet that has data in it */ 336 337 if (dlen == 0) 338 return; 339 340 p = (char *)pip; 341 p += hlen; 342 343 bcopy(p, p + slen, dlen); 344 memcpy(p, buffer, slen); 345 } 346 347 /* Save information about modfied sequence number */ 348 { 349 int delta; 350 351 SetAckModified(lnk); 352 tc = (struct tcphdr *)ip_next(pip); 353 delta = GetDeltaSeqOut(tc->th_seq, lnk); 354 AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq, 355 tc->th_off); 356 } 357 358 /* Update IP header packet length and checksum */ 359 { 360 int accumulate; 361 362 accumulate = pip->ip_len; 363 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 364 accumulate -= pip->ip_len; 365 366 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 367 } 368 369 /* Update TCP checksum, Use TcpChecksum since so many things have 370 already changed. */ 371 372 tc->th_sum = 0; 373 #ifdef _KERNEL 374 tc->th_x2 = 1; 375 #else 376 tc->th_sum = TcpChecksum(pip); 377 #endif 378 } 379 380 static void 381 ProxyEncodeIpHeader(struct ip *pip, 382 int maxpacketsize) 383 { 384 #define OPTION_LEN_BYTES 8 385 #define OPTION_LEN_INT16 4 386 #define OPTION_LEN_INT32 2 387 u_char option[OPTION_LEN_BYTES]; 388 389 #ifdef LIBALIAS_DEBUG 390 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 391 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 392 #endif 393 394 (void)maxpacketsize; 395 396 /* Check to see that there is room to add an IP option */ 397 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 398 return; 399 400 /* Build option and copy into packet */ 401 { 402 u_char *ptr; 403 struct tcphdr *tc; 404 405 ptr = (u_char *) pip; 406 ptr += 20; 407 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 408 409 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 410 option[1] = OPTION_LEN_BYTES; 411 412 memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 413 414 tc = (struct tcphdr *)ip_next(pip); 415 memcpy(&option[6], (u_char *) & tc->th_sport, 2); 416 417 memcpy(ptr, option, 8); 418 } 419 420 /* Update checksum, header length and packet length */ 421 { 422 int i; 423 int accumulate; 424 u_short *sptr; 425 426 sptr = (u_short *) option; 427 accumulate = 0; 428 for (i = 0; i < OPTION_LEN_INT16; i++) 429 accumulate -= *(sptr++); 430 431 sptr = (u_short *) pip; 432 accumulate += *sptr; 433 pip->ip_hl += OPTION_LEN_INT32; 434 accumulate -= *sptr; 435 436 accumulate += pip->ip_len; 437 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 438 accumulate -= pip->ip_len; 439 440 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 441 } 442 #undef OPTION_LEN_BYTES 443 #undef OPTION_LEN_INT16 444 #undef OPTION_LEN_INT32 445 #ifdef LIBALIAS_DEBUG 446 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 447 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 448 #endif 449 } 450 451 452 /* Functions by other packet alias source files 453 454 ProxyCheck() -- Checks whether an outgoing packet should 455 be proxied. 456 ProxyModify() -- Encodes the original destination address/port 457 for a packet which is to be redirected to 458 a proxy server. 459 */ 460 461 int 462 ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr, 463 u_short * proxy_server_port, struct in_addr src_addr, 464 struct in_addr dst_addr, u_short dst_port, u_char ip_p) 465 { 466 struct proxy_entry *ptr; 467 468 LIBALIAS_LOCK_ASSERT(la); 469 470 ptr = la->proxyList; 471 while (ptr != NULL) { 472 u_short proxy_port; 473 474 proxy_port = ptr->proxy_port; 475 if ((dst_port == proxy_port || proxy_port == 0) 476 && ip_p == ptr->proto 477 && src_addr.s_addr != ptr->server_addr.s_addr) { 478 struct in_addr src_addr_masked; 479 struct in_addr dst_addr_masked; 480 481 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 482 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 483 484 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 485 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 486 if ((*proxy_server_port = ptr->server_port) == 0) 487 *proxy_server_port = dst_port; 488 *proxy_server_addr = ptr->server_addr; 489 return (ptr->proxy_type); 490 } 491 } 492 ptr = ptr->next; 493 } 494 495 return (0); 496 } 497 498 void 499 ProxyModify(struct libalias *la, struct alias_link *lnk, 500 struct ip *pip, 501 int maxpacketsize, 502 int proxy_type) 503 { 504 505 LIBALIAS_LOCK_ASSERT(la); 506 (void)la; 507 508 switch (proxy_type) { 509 case PROXY_TYPE_ENCODE_IPHDR: 510 ProxyEncodeIpHeader(pip, maxpacketsize); 511 break; 512 513 case PROXY_TYPE_ENCODE_TCPSTREAM: 514 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 515 break; 516 } 517 } 518 519 520 /* 521 Public API functions 522 */ 523 524 int 525 LibAliasProxyRule(struct libalias *la, const char *cmd) 526 { 527 /* 528 * This function takes command strings of the form: 529 * 530 * server <addr>[:<port>] 531 * [port <port>] 532 * [rule n] 533 * [proto tcp|udp] 534 * [src <addr>[/n]] 535 * [dst <addr>[/n]] 536 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 537 * 538 * delete <rule number> 539 * 540 * Subfields can be in arbitrary order. Port numbers and addresses 541 * must be in either numeric or symbolic form. An optional rule number 542 * is used to control the order in which rules are searched. If two 543 * rules have the same number, then search order cannot be guaranteed, 544 * and the rules should be disjoint. If no rule number is specified, 545 * then 0 is used, and group 0 rules are always checked before any 546 * others. 547 */ 548 int i, n, len, ret; 549 int cmd_len; 550 int token_count; 551 int state; 552 char *token; 553 char buffer[256]; 554 char str_port[sizeof(buffer)]; 555 char str_server_port[sizeof(buffer)]; 556 char *res = buffer; 557 558 int rule_index; 559 int proto; 560 int proxy_type; 561 int proxy_port; 562 int server_port; 563 struct in_addr server_addr; 564 struct in_addr src_addr, src_mask; 565 struct in_addr dst_addr, dst_mask; 566 struct proxy_entry *proxy_entry; 567 568 LIBALIAS_LOCK(la); 569 ret = 0; 570 /* Copy command line into a buffer */ 571 cmd += strspn(cmd, " \t"); 572 cmd_len = strlen(cmd); 573 if (cmd_len > (int)(sizeof(buffer) - 1)) { 574 ret = -1; 575 goto getout; 576 } 577 strcpy(buffer, cmd); 578 579 /* Convert to lower case */ 580 len = strlen(buffer); 581 for (i = 0; i < len; i++) 582 buffer[i] = tolower((unsigned char)buffer[i]); 583 584 /* Set default proxy type */ 585 586 /* Set up default values */ 587 rule_index = 0; 588 proxy_type = PROXY_TYPE_ENCODE_NONE; 589 proto = IPPROTO_TCP; 590 proxy_port = 0; 591 server_addr.s_addr = 0; 592 server_port = 0; 593 src_addr.s_addr = 0; 594 IpMask(0, &src_mask); 595 dst_addr.s_addr = 0; 596 IpMask(0, &dst_mask); 597 598 str_port[0] = 0; 599 str_server_port[0] = 0; 600 601 /* Parse command string with state machine */ 602 #define STATE_READ_KEYWORD 0 603 #define STATE_READ_TYPE 1 604 #define STATE_READ_PORT 2 605 #define STATE_READ_SERVER 3 606 #define STATE_READ_RULE 4 607 #define STATE_READ_DELETE 5 608 #define STATE_READ_PROTO 6 609 #define STATE_READ_SRC 7 610 #define STATE_READ_DST 8 611 state = STATE_READ_KEYWORD; 612 token = strsep(&res, " \t"); 613 token_count = 0; 614 while (token != NULL) { 615 token_count++; 616 switch (state) { 617 case STATE_READ_KEYWORD: 618 if (strcmp(token, "type") == 0) 619 state = STATE_READ_TYPE; 620 else if (strcmp(token, "port") == 0) 621 state = STATE_READ_PORT; 622 else if (strcmp(token, "server") == 0) 623 state = STATE_READ_SERVER; 624 else if (strcmp(token, "rule") == 0) 625 state = STATE_READ_RULE; 626 else if (strcmp(token, "delete") == 0) 627 state = STATE_READ_DELETE; 628 else if (strcmp(token, "proto") == 0) 629 state = STATE_READ_PROTO; 630 else if (strcmp(token, "src") == 0) 631 state = STATE_READ_SRC; 632 else if (strcmp(token, "dst") == 0) 633 state = STATE_READ_DST; 634 else { 635 ret = -1; 636 goto getout; 637 } 638 break; 639 640 case STATE_READ_TYPE: 641 if (strcmp(token, "encode_ip_hdr") == 0) 642 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 643 else if (strcmp(token, "encode_tcp_stream") == 0) 644 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 645 else if (strcmp(token, "no_encode") == 0) 646 proxy_type = PROXY_TYPE_ENCODE_NONE; 647 else { 648 ret = -1; 649 goto getout; 650 } 651 state = STATE_READ_KEYWORD; 652 break; 653 654 case STATE_READ_PORT: 655 strcpy(str_port, token); 656 state = STATE_READ_KEYWORD; 657 break; 658 659 case STATE_READ_SERVER: 660 { 661 int err; 662 char *p; 663 char s[sizeof(buffer)]; 664 665 p = token; 666 while (*p != ':' && *p != 0) 667 p++; 668 669 if (*p != ':') { 670 err = IpAddr(token, &server_addr); 671 if (err) { 672 ret = -1; 673 goto getout; 674 } 675 } else { 676 *p = ' '; 677 678 n = sscanf(token, "%s %s", s, str_server_port); 679 if (n != 2) { 680 ret = -1; 681 goto getout; 682 } 683 684 err = IpAddr(s, &server_addr); 685 if (err) { 686 ret = -1; 687 goto getout; 688 } 689 } 690 } 691 state = STATE_READ_KEYWORD; 692 break; 693 694 case STATE_READ_RULE: 695 n = sscanf(token, "%d", &rule_index); 696 if (n != 1 || rule_index < 0) { 697 ret = -1; 698 goto getout; 699 } 700 state = STATE_READ_KEYWORD; 701 break; 702 703 case STATE_READ_DELETE: 704 { 705 int err; 706 int rule_to_delete; 707 708 if (token_count != 2) { 709 ret = -1; 710 goto getout; 711 } 712 713 n = sscanf(token, "%d", &rule_to_delete); 714 if (n != 1) { 715 ret = -1; 716 goto getout; 717 } 718 err = RuleNumberDelete(la, rule_to_delete); 719 if (err) 720 ret = -1; 721 ret = 0; 722 goto getout; 723 } 724 725 case STATE_READ_PROTO: 726 if (strcmp(token, "tcp") == 0) 727 proto = IPPROTO_TCP; 728 else if (strcmp(token, "udp") == 0) 729 proto = IPPROTO_UDP; 730 else { 731 ret = -1; 732 goto getout; 733 } 734 state = STATE_READ_KEYWORD; 735 break; 736 737 case STATE_READ_SRC: 738 case STATE_READ_DST: 739 { 740 int err; 741 char *p; 742 struct in_addr mask; 743 struct in_addr addr; 744 745 p = token; 746 while (*p != '/' && *p != 0) 747 p++; 748 749 if (*p != '/') { 750 IpMask(32, &mask); 751 err = IpAddr(token, &addr); 752 if (err) { 753 ret = -1; 754 goto getout; 755 } 756 } else { 757 int nbits; 758 char s[sizeof(buffer)]; 759 760 *p = ' '; 761 n = sscanf(token, "%s %d", s, &nbits); 762 if (n != 2) { 763 ret = -1; 764 goto getout; 765 } 766 767 err = IpAddr(s, &addr); 768 if (err) { 769 ret = -1; 770 goto getout; 771 } 772 773 err = IpMask(nbits, &mask); 774 if (err) { 775 ret = -1; 776 goto getout; 777 } 778 } 779 780 if (state == STATE_READ_SRC) { 781 src_addr = addr; 782 src_mask = mask; 783 } else { 784 dst_addr = addr; 785 dst_mask = mask; 786 } 787 } 788 state = STATE_READ_KEYWORD; 789 break; 790 791 default: 792 ret = -1; 793 goto getout; 794 break; 795 } 796 797 do { 798 token = strsep(&res, " \t"); 799 } while (token != NULL && !*token); 800 } 801 #undef STATE_READ_KEYWORD 802 #undef STATE_READ_TYPE 803 #undef STATE_READ_PORT 804 #undef STATE_READ_SERVER 805 #undef STATE_READ_RULE 806 #undef STATE_READ_DELETE 807 #undef STATE_READ_PROTO 808 #undef STATE_READ_SRC 809 #undef STATE_READ_DST 810 811 /* Convert port strings to numbers. This needs to be done after 812 the string is parsed, because the prototype might not be designated 813 before the ports (which might be symbolic entries in /etc/services) */ 814 815 if (strlen(str_port) != 0) { 816 int err; 817 818 err = IpPort(str_port, proto, &proxy_port); 819 if (err) { 820 ret = -1; 821 goto getout; 822 } 823 } else { 824 proxy_port = 0; 825 } 826 827 if (strlen(str_server_port) != 0) { 828 int err; 829 830 err = IpPort(str_server_port, proto, &server_port); 831 if (err) { 832 ret = -1; 833 goto getout; 834 } 835 } else { 836 server_port = 0; 837 } 838 839 /* Check that at least the server address has been defined */ 840 if (server_addr.s_addr == 0) { 841 ret = -1; 842 goto getout; 843 } 844 845 /* Add to linked list */ 846 proxy_entry = malloc(sizeof(struct proxy_entry)); 847 if (proxy_entry == NULL) { 848 ret = -1; 849 goto getout; 850 } 851 852 proxy_entry->proxy_type = proxy_type; 853 proxy_entry->rule_index = rule_index; 854 proxy_entry->proto = proto; 855 proxy_entry->proxy_port = htons(proxy_port); 856 proxy_entry->server_port = htons(server_port); 857 proxy_entry->server_addr = server_addr; 858 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 859 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 860 proxy_entry->src_mask = src_mask; 861 proxy_entry->dst_mask = dst_mask; 862 863 RuleAdd(la, proxy_entry); 864 865 getout: 866 LIBALIAS_UNLOCK(la); 867 return (ret); 868 } 869