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 #ifdef _KERNEL /* XXX: can it be moved to libkern? */ 141 static int inet_aton(const char *cp, struct in_addr *addr); 142 #endif 143 static int IpMask(int, struct in_addr *); 144 static int IpAddr(char *, struct in_addr *); 145 static int IpPort(char *, int, int *); 146 static void RuleAdd(struct libalias *la, struct proxy_entry *); 147 static void RuleDelete(struct proxy_entry *); 148 static int RuleNumberDelete(struct libalias *la, int); 149 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 150 static void ProxyEncodeIpHeader(struct ip *, int); 151 152 #ifdef _KERNEL 153 static int 154 inet_aton(cp, addr) 155 const char *cp; 156 struct in_addr *addr; 157 { 158 u_long parts[4]; 159 in_addr_t val; 160 const char *c; 161 char *endptr; 162 int gotend, n; 163 164 c = (const char *)cp; 165 n = 0; 166 /* 167 * Run through the string, grabbing numbers until 168 * the end of the string, or some error 169 */ 170 gotend = 0; 171 while (!gotend) { 172 unsigned long l; 173 174 l = strtoul(c, &endptr, 0); 175 176 if (l == ULONG_MAX || (l == 0 && endptr == c)) 177 return (0); 178 179 val = (in_addr_t)l; 180 /* 181 * If the whole string is invalid, endptr will equal 182 * c.. this way we can make sure someone hasn't 183 * gone '.12' or something which would get past 184 * the next check. 185 */ 186 if (endptr == c) 187 return (0); 188 parts[n] = val; 189 c = endptr; 190 191 /* Check the next character past the previous number's end */ 192 switch (*c) { 193 case '.' : 194 /* Make sure we only do 3 dots .. */ 195 if (n == 3) /* Whoops. Quit. */ 196 return (0); 197 n++; 198 c++; 199 break; 200 201 case '\0': 202 gotend = 1; 203 break; 204 205 default: 206 if (isspace((unsigned char)*c)) { 207 gotend = 1; 208 break; 209 } else 210 return (0); /* Invalid character, so fail */ 211 } 212 213 } 214 215 /* 216 * Concoct the address according to 217 * the number of parts specified. 218 */ 219 220 switch (n) { 221 case 0: /* a -- 32 bits */ 222 /* 223 * Nothing is necessary here. Overflow checking was 224 * already done in strtoul(). 225 */ 226 break; 227 case 1: /* a.b -- 8.24 bits */ 228 if (val > 0xffffff || parts[0] > 0xff) 229 return (0); 230 val |= parts[0] << 24; 231 break; 232 233 case 2: /* a.b.c -- 8.8.16 bits */ 234 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) 235 return (0); 236 val |= (parts[0] << 24) | (parts[1] << 16); 237 break; 238 239 case 3: /* a.b.c.d -- 8.8.8.8 bits */ 240 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || 241 parts[2] > 0xff) 242 return (0); 243 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 244 break; 245 } 246 247 if (addr != NULL) 248 addr->s_addr = htonl(val); 249 return (1); 250 } 251 #endif 252 253 static int 254 IpMask(int nbits, struct in_addr *mask) 255 { 256 int i; 257 u_int imask; 258 259 if (nbits < 0 || nbits > 32) 260 return (-1); 261 262 imask = 0; 263 for (i = 0; i < nbits; i++) 264 imask = (imask >> 1) + 0x80000000; 265 mask->s_addr = htonl(imask); 266 267 return (0); 268 } 269 270 static int 271 IpAddr(char *s, struct in_addr *addr) 272 { 273 if (inet_aton(s, addr) == 0) 274 return (-1); 275 else 276 return (0); 277 } 278 279 static int 280 IpPort(char *s, int proto, int *port) 281 { 282 int n; 283 284 n = sscanf(s, "%d", port); 285 if (n != 1) 286 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */ 287 { 288 struct servent *se; 289 290 if (proto == IPPROTO_TCP) 291 se = getservbyname(s, "tcp"); 292 else if (proto == IPPROTO_UDP) 293 se = getservbyname(s, "udp"); 294 else 295 return (-1); 296 297 if (se == NULL) 298 return (-1); 299 300 *port = (u_int) ntohs(se->s_port); 301 } 302 #else 303 return (-1); 304 #endif 305 return (0); 306 } 307 308 void 309 RuleAdd(struct libalias *la, struct proxy_entry *entry) 310 { 311 int rule_index; 312 struct proxy_entry *ptr; 313 struct proxy_entry *ptr_last; 314 315 LIBALIAS_LOCK_ASSERT(la); 316 317 if (la->proxyList == NULL) { 318 la->proxyList = entry; 319 entry->last = NULL; 320 entry->next = NULL; 321 return; 322 } 323 entry->la = la; 324 325 rule_index = entry->rule_index; 326 ptr = la->proxyList; 327 ptr_last = NULL; 328 while (ptr != NULL) { 329 if (ptr->rule_index >= rule_index) { 330 if (ptr_last == NULL) { 331 entry->next = la->proxyList; 332 entry->last = NULL; 333 la->proxyList->last = entry; 334 la->proxyList = entry; 335 return; 336 } 337 ptr_last->next = entry; 338 ptr->last = entry; 339 entry->last = ptr->last; 340 entry->next = ptr; 341 return; 342 } 343 ptr_last = ptr; 344 ptr = ptr->next; 345 } 346 347 ptr_last->next = entry; 348 entry->last = ptr_last; 349 entry->next = NULL; 350 } 351 352 static void 353 RuleDelete(struct proxy_entry *entry) 354 { 355 struct libalias *la; 356 357 la = entry->la; 358 LIBALIAS_LOCK_ASSERT(la); 359 if (entry->last != NULL) 360 entry->last->next = entry->next; 361 else 362 la->proxyList = entry->next; 363 364 if (entry->next != NULL) 365 entry->next->last = entry->last; 366 367 free(entry); 368 } 369 370 static int 371 RuleNumberDelete(struct libalias *la, int rule_index) 372 { 373 int err; 374 struct proxy_entry *ptr; 375 376 LIBALIAS_LOCK_ASSERT(la); 377 err = -1; 378 ptr = la->proxyList; 379 while (ptr != NULL) { 380 struct proxy_entry *ptr_next; 381 382 ptr_next = ptr->next; 383 if (ptr->rule_index == rule_index) { 384 err = 0; 385 RuleDelete(ptr); 386 } 387 ptr = ptr_next; 388 } 389 390 return (err); 391 } 392 393 static void 394 ProxyEncodeTcpStream(struct alias_link *lnk, 395 struct ip *pip, 396 int maxpacketsize) 397 { 398 int slen; 399 char buffer[40]; 400 struct tcphdr *tc; 401 402 /* Compute pointer to tcp header */ 403 tc = (struct tcphdr *)ip_next(pip); 404 405 /* Don't modify if once already modified */ 406 407 if (GetAckModified(lnk)) 408 return; 409 410 /* Translate destination address and port to string form */ 411 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 412 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 413 414 /* Pad string out to a multiple of two in length */ 415 slen = strlen(buffer); 416 switch (slen % 2) { 417 case 0: 418 strcat(buffer, " \n"); 419 slen += 2; 420 break; 421 case 1: 422 strcat(buffer, "\n"); 423 slen += 1; 424 } 425 426 /* Check for packet overflow */ 427 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 428 return; 429 430 /* Shift existing TCP data and insert destination string */ 431 { 432 int dlen; 433 int hlen; 434 char *p; 435 436 hlen = (pip->ip_hl + tc->th_off) << 2; 437 dlen = ntohs(pip->ip_len) - hlen; 438 439 /* Modify first packet that has data in it */ 440 441 if (dlen == 0) 442 return; 443 444 p = (char *)pip; 445 p += hlen; 446 447 bcopy(p, p + slen, dlen); 448 memcpy(p, buffer, slen); 449 } 450 451 /* Save information about modfied sequence number */ 452 { 453 int delta; 454 455 SetAckModified(lnk); 456 delta = GetDeltaSeqOut(pip, lnk); 457 AddSeq(pip, lnk, delta + slen); 458 } 459 460 /* Update IP header packet length and checksum */ 461 { 462 int accumulate; 463 464 accumulate = pip->ip_len; 465 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 466 accumulate -= pip->ip_len; 467 468 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 469 } 470 471 /* Update TCP checksum, Use TcpChecksum since so many things have 472 already changed. */ 473 474 tc->th_sum = 0; 475 #ifdef _KERNEL 476 tc->th_x2 = 1; 477 #else 478 tc->th_sum = TcpChecksum(pip); 479 #endif 480 } 481 482 static void 483 ProxyEncodeIpHeader(struct ip *pip, 484 int maxpacketsize) 485 { 486 #define OPTION_LEN_BYTES 8 487 #define OPTION_LEN_INT16 4 488 #define OPTION_LEN_INT32 2 489 u_char option[OPTION_LEN_BYTES]; 490 491 #ifdef LIBALIAS_DEBUG 492 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 493 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 494 #endif 495 496 (void)maxpacketsize; 497 498 /* Check to see that there is room to add an IP option */ 499 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 500 return; 501 502 /* Build option and copy into packet */ 503 { 504 u_char *ptr; 505 struct tcphdr *tc; 506 507 ptr = (u_char *) pip; 508 ptr += 20; 509 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 510 511 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 512 option[1] = OPTION_LEN_BYTES; 513 514 memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 515 516 tc = (struct tcphdr *)ip_next(pip); 517 memcpy(&option[6], (u_char *) & tc->th_sport, 2); 518 519 memcpy(ptr, option, 8); 520 } 521 522 /* Update checksum, header length and packet length */ 523 { 524 int i; 525 int accumulate; 526 u_short *sptr; 527 528 sptr = (u_short *) option; 529 accumulate = 0; 530 for (i = 0; i < OPTION_LEN_INT16; i++) 531 accumulate -= *(sptr++); 532 533 sptr = (u_short *) pip; 534 accumulate += *sptr; 535 pip->ip_hl += OPTION_LEN_INT32; 536 accumulate -= *sptr; 537 538 accumulate += pip->ip_len; 539 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 540 accumulate -= pip->ip_len; 541 542 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 543 } 544 #undef OPTION_LEN_BYTES 545 #undef OPTION_LEN_INT16 546 #undef OPTION_LEN_INT32 547 #ifdef LIBALIAS_DEBUG 548 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 549 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 550 #endif 551 } 552 553 554 /* Functions by other packet alias source files 555 556 ProxyCheck() -- Checks whether an outgoing packet should 557 be proxied. 558 ProxyModify() -- Encodes the original destination address/port 559 for a packet which is to be redirected to 560 a proxy server. 561 */ 562 563 int 564 ProxyCheck(struct libalias *la, struct ip *pip, 565 struct in_addr *proxy_server_addr, 566 u_short * proxy_server_port) 567 { 568 u_short dst_port; 569 struct in_addr src_addr; 570 struct in_addr dst_addr; 571 struct proxy_entry *ptr; 572 573 LIBALIAS_LOCK_ASSERT(la); 574 src_addr = pip->ip_src; 575 dst_addr = pip->ip_dst; 576 dst_port = ((struct tcphdr *)ip_next(pip)) 577 ->th_dport; 578 579 ptr = la->proxyList; 580 while (ptr != NULL) { 581 u_short proxy_port; 582 583 proxy_port = ptr->proxy_port; 584 if ((dst_port == proxy_port || proxy_port == 0) 585 && pip->ip_p == ptr->proto 586 && src_addr.s_addr != ptr->server_addr.s_addr) { 587 struct in_addr src_addr_masked; 588 struct in_addr dst_addr_masked; 589 590 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 591 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 592 593 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 594 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 595 if ((*proxy_server_port = ptr->server_port) == 0) 596 *proxy_server_port = dst_port; 597 *proxy_server_addr = ptr->server_addr; 598 return (ptr->proxy_type); 599 } 600 } 601 ptr = ptr->next; 602 } 603 604 return (0); 605 } 606 607 void 608 ProxyModify(struct libalias *la, struct alias_link *lnk, 609 struct ip *pip, 610 int maxpacketsize, 611 int proxy_type) 612 { 613 614 LIBALIAS_LOCK_ASSERT(la); 615 (void)la; 616 617 switch (proxy_type) { 618 case PROXY_TYPE_ENCODE_IPHDR: 619 ProxyEncodeIpHeader(pip, maxpacketsize); 620 break; 621 622 case PROXY_TYPE_ENCODE_TCPSTREAM: 623 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 624 break; 625 } 626 } 627 628 629 /* 630 Public API functions 631 */ 632 633 int 634 LibAliasProxyRule(struct libalias *la, const char *cmd) 635 { 636 /* 637 * This function takes command strings of the form: 638 * 639 * server <addr>[:<port>] 640 * [port <port>] 641 * [rule n] 642 * [proto tcp|udp] 643 * [src <addr>[/n]] 644 * [dst <addr>[/n]] 645 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 646 * 647 * delete <rule number> 648 * 649 * Subfields can be in arbitrary order. Port numbers and addresses 650 * must be in either numeric or symbolic form. An optional rule number 651 * is used to control the order in which rules are searched. If two 652 * rules have the same number, then search order cannot be guaranteed, 653 * and the rules should be disjoint. If no rule number is specified, 654 * then 0 is used, and group 0 rules are always checked before any 655 * others. 656 */ 657 int i, n, len, ret; 658 int cmd_len; 659 int token_count; 660 int state; 661 char *token; 662 char buffer[256]; 663 char str_port[sizeof(buffer)]; 664 char str_server_port[sizeof(buffer)]; 665 char *res = buffer; 666 667 int rule_index; 668 int proto; 669 int proxy_type; 670 int proxy_port; 671 int server_port; 672 struct in_addr server_addr; 673 struct in_addr src_addr, src_mask; 674 struct in_addr dst_addr, dst_mask; 675 struct proxy_entry *proxy_entry; 676 677 LIBALIAS_LOCK(la); 678 ret = 0; 679 /* Copy command line into a buffer */ 680 cmd += strspn(cmd, " \t"); 681 cmd_len = strlen(cmd); 682 if (cmd_len > (int)(sizeof(buffer) - 1)) { 683 ret = -1; 684 goto getout; 685 } 686 strcpy(buffer, cmd); 687 688 /* Convert to lower case */ 689 len = strlen(buffer); 690 for (i = 0; i < len; i++) 691 buffer[i] = tolower((unsigned char)buffer[i]); 692 693 /* Set default proxy type */ 694 695 /* Set up default values */ 696 rule_index = 0; 697 proxy_type = PROXY_TYPE_ENCODE_NONE; 698 proto = IPPROTO_TCP; 699 proxy_port = 0; 700 server_addr.s_addr = 0; 701 server_port = 0; 702 src_addr.s_addr = 0; 703 IpMask(0, &src_mask); 704 dst_addr.s_addr = 0; 705 IpMask(0, &dst_mask); 706 707 str_port[0] = 0; 708 str_server_port[0] = 0; 709 710 /* Parse command string with state machine */ 711 #define STATE_READ_KEYWORD 0 712 #define STATE_READ_TYPE 1 713 #define STATE_READ_PORT 2 714 #define STATE_READ_SERVER 3 715 #define STATE_READ_RULE 4 716 #define STATE_READ_DELETE 5 717 #define STATE_READ_PROTO 6 718 #define STATE_READ_SRC 7 719 #define STATE_READ_DST 8 720 state = STATE_READ_KEYWORD; 721 token = strsep(&res, " \t"); 722 token_count = 0; 723 while (token != NULL) { 724 token_count++; 725 switch (state) { 726 case STATE_READ_KEYWORD: 727 if (strcmp(token, "type") == 0) 728 state = STATE_READ_TYPE; 729 else if (strcmp(token, "port") == 0) 730 state = STATE_READ_PORT; 731 else if (strcmp(token, "server") == 0) 732 state = STATE_READ_SERVER; 733 else if (strcmp(token, "rule") == 0) 734 state = STATE_READ_RULE; 735 else if (strcmp(token, "delete") == 0) 736 state = STATE_READ_DELETE; 737 else if (strcmp(token, "proto") == 0) 738 state = STATE_READ_PROTO; 739 else if (strcmp(token, "src") == 0) 740 state = STATE_READ_SRC; 741 else if (strcmp(token, "dst") == 0) 742 state = STATE_READ_DST; 743 else { 744 ret = -1; 745 goto getout; 746 } 747 break; 748 749 case STATE_READ_TYPE: 750 if (strcmp(token, "encode_ip_hdr") == 0) 751 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 752 else if (strcmp(token, "encode_tcp_stream") == 0) 753 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 754 else if (strcmp(token, "no_encode") == 0) 755 proxy_type = PROXY_TYPE_ENCODE_NONE; 756 else { 757 ret = -1; 758 goto getout; 759 } 760 state = STATE_READ_KEYWORD; 761 break; 762 763 case STATE_READ_PORT: 764 strcpy(str_port, token); 765 state = STATE_READ_KEYWORD; 766 break; 767 768 case STATE_READ_SERVER: 769 { 770 int err; 771 char *p; 772 char s[sizeof(buffer)]; 773 774 p = token; 775 while (*p != ':' && *p != 0) 776 p++; 777 778 if (*p != ':') { 779 err = IpAddr(token, &server_addr); 780 if (err) { 781 ret = -1; 782 goto getout; 783 } 784 } else { 785 *p = ' '; 786 787 n = sscanf(token, "%s %s", s, str_server_port); 788 if (n != 2) { 789 ret = -1; 790 goto getout; 791 } 792 793 err = IpAddr(s, &server_addr); 794 if (err) { 795 ret = -1; 796 goto getout; 797 } 798 } 799 } 800 state = STATE_READ_KEYWORD; 801 break; 802 803 case STATE_READ_RULE: 804 n = sscanf(token, "%d", &rule_index); 805 if (n != 1 || rule_index < 0) { 806 ret = -1; 807 goto getout; 808 } 809 state = STATE_READ_KEYWORD; 810 break; 811 812 case STATE_READ_DELETE: 813 { 814 int err; 815 int rule_to_delete; 816 817 if (token_count != 2) { 818 ret = -1; 819 goto getout; 820 } 821 822 n = sscanf(token, "%d", &rule_to_delete); 823 if (n != 1) { 824 ret = -1; 825 goto getout; 826 } 827 err = RuleNumberDelete(la, rule_to_delete); 828 if (err) 829 ret = -1; 830 ret = 0; 831 goto getout; 832 } 833 834 case STATE_READ_PROTO: 835 if (strcmp(token, "tcp") == 0) 836 proto = IPPROTO_TCP; 837 else if (strcmp(token, "udp") == 0) 838 proto = IPPROTO_UDP; 839 else { 840 ret = -1; 841 goto getout; 842 } 843 state = STATE_READ_KEYWORD; 844 break; 845 846 case STATE_READ_SRC: 847 case STATE_READ_DST: 848 { 849 int err; 850 char *p; 851 struct in_addr mask; 852 struct in_addr addr; 853 854 p = token; 855 while (*p != '/' && *p != 0) 856 p++; 857 858 if (*p != '/') { 859 IpMask(32, &mask); 860 err = IpAddr(token, &addr); 861 if (err) { 862 ret = -1; 863 goto getout; 864 } 865 } else { 866 int nbits; 867 char s[sizeof(buffer)]; 868 869 *p = ' '; 870 n = sscanf(token, "%s %d", s, &nbits); 871 if (n != 2) { 872 ret = -1; 873 goto getout; 874 } 875 876 err = IpAddr(s, &addr); 877 if (err) { 878 ret = -1; 879 goto getout; 880 } 881 882 err = IpMask(nbits, &mask); 883 if (err) { 884 ret = -1; 885 goto getout; 886 } 887 } 888 889 if (state == STATE_READ_SRC) { 890 src_addr = addr; 891 src_mask = mask; 892 } else { 893 dst_addr = addr; 894 dst_mask = mask; 895 } 896 } 897 state = STATE_READ_KEYWORD; 898 break; 899 900 default: 901 ret = -1; 902 goto getout; 903 break; 904 } 905 906 do { 907 token = strsep(&res, " \t"); 908 } while (token != NULL && !*token); 909 } 910 #undef STATE_READ_KEYWORD 911 #undef STATE_READ_TYPE 912 #undef STATE_READ_PORT 913 #undef STATE_READ_SERVER 914 #undef STATE_READ_RULE 915 #undef STATE_READ_DELETE 916 #undef STATE_READ_PROTO 917 #undef STATE_READ_SRC 918 #undef STATE_READ_DST 919 920 /* Convert port strings to numbers. This needs to be done after 921 the string is parsed, because the prototype might not be designated 922 before the ports (which might be symbolic entries in /etc/services) */ 923 924 if (strlen(str_port) != 0) { 925 int err; 926 927 err = IpPort(str_port, proto, &proxy_port); 928 if (err) { 929 ret = -1; 930 goto getout; 931 } 932 } else { 933 proxy_port = 0; 934 } 935 936 if (strlen(str_server_port) != 0) { 937 int err; 938 939 err = IpPort(str_server_port, proto, &server_port); 940 if (err) { 941 ret = -1; 942 goto getout; 943 } 944 } else { 945 server_port = 0; 946 } 947 948 /* Check that at least the server address has been defined */ 949 if (server_addr.s_addr == 0) { 950 ret = -1; 951 goto getout; 952 } 953 954 /* Add to linked list */ 955 proxy_entry = malloc(sizeof(struct proxy_entry)); 956 if (proxy_entry == NULL) { 957 ret = -1; 958 goto getout; 959 } 960 961 proxy_entry->proxy_type = proxy_type; 962 proxy_entry->rule_index = rule_index; 963 proxy_entry->proto = proto; 964 proxy_entry->proxy_port = htons(proxy_port); 965 proxy_entry->server_port = htons(server_port); 966 proxy_entry->server_addr = server_addr; 967 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 968 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 969 proxy_entry->src_mask = src_mask; 970 proxy_entry->dst_mask = dst_mask; 971 972 RuleAdd(la, proxy_entry); 973 974 getout: 975 LIBALIAS_UNLOCK(la); 976 return (ret); 977 } 978