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 tc = (struct tcphdr *)ip_next(pip); 457 delta = GetDeltaSeqOut(tc->th_seq, lnk); 458 AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq, 459 tc->th_off); 460 } 461 462 /* Update IP header packet length and checksum */ 463 { 464 int accumulate; 465 466 accumulate = pip->ip_len; 467 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 468 accumulate -= pip->ip_len; 469 470 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 471 } 472 473 /* Update TCP checksum, Use TcpChecksum since so many things have 474 already changed. */ 475 476 tc->th_sum = 0; 477 #ifdef _KERNEL 478 tc->th_x2 = 1; 479 #else 480 tc->th_sum = TcpChecksum(pip); 481 #endif 482 } 483 484 static void 485 ProxyEncodeIpHeader(struct ip *pip, 486 int maxpacketsize) 487 { 488 #define OPTION_LEN_BYTES 8 489 #define OPTION_LEN_INT16 4 490 #define OPTION_LEN_INT32 2 491 u_char option[OPTION_LEN_BYTES]; 492 493 #ifdef LIBALIAS_DEBUG 494 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 495 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 496 #endif 497 498 (void)maxpacketsize; 499 500 /* Check to see that there is room to add an IP option */ 501 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 502 return; 503 504 /* Build option and copy into packet */ 505 { 506 u_char *ptr; 507 struct tcphdr *tc; 508 509 ptr = (u_char *) pip; 510 ptr += 20; 511 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 512 513 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 514 option[1] = OPTION_LEN_BYTES; 515 516 memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 517 518 tc = (struct tcphdr *)ip_next(pip); 519 memcpy(&option[6], (u_char *) & tc->th_sport, 2); 520 521 memcpy(ptr, option, 8); 522 } 523 524 /* Update checksum, header length and packet length */ 525 { 526 int i; 527 int accumulate; 528 u_short *sptr; 529 530 sptr = (u_short *) option; 531 accumulate = 0; 532 for (i = 0; i < OPTION_LEN_INT16; i++) 533 accumulate -= *(sptr++); 534 535 sptr = (u_short *) pip; 536 accumulate += *sptr; 537 pip->ip_hl += OPTION_LEN_INT32; 538 accumulate -= *sptr; 539 540 accumulate += pip->ip_len; 541 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 542 accumulate -= pip->ip_len; 543 544 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 545 } 546 #undef OPTION_LEN_BYTES 547 #undef OPTION_LEN_INT16 548 #undef OPTION_LEN_INT32 549 #ifdef LIBALIAS_DEBUG 550 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 551 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 552 #endif 553 } 554 555 556 /* Functions by other packet alias source files 557 558 ProxyCheck() -- Checks whether an outgoing packet should 559 be proxied. 560 ProxyModify() -- Encodes the original destination address/port 561 for a packet which is to be redirected to 562 a proxy server. 563 */ 564 565 int 566 ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr, 567 u_short * proxy_server_port, struct in_addr src_addr, 568 struct in_addr dst_addr, u_short dst_port, u_char ip_p) 569 { 570 struct proxy_entry *ptr; 571 572 LIBALIAS_LOCK_ASSERT(la); 573 574 ptr = la->proxyList; 575 while (ptr != NULL) { 576 u_short proxy_port; 577 578 proxy_port = ptr->proxy_port; 579 if ((dst_port == proxy_port || proxy_port == 0) 580 && ip_p == ptr->proto 581 && src_addr.s_addr != ptr->server_addr.s_addr) { 582 struct in_addr src_addr_masked; 583 struct in_addr dst_addr_masked; 584 585 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 586 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 587 588 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 589 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 590 if ((*proxy_server_port = ptr->server_port) == 0) 591 *proxy_server_port = dst_port; 592 *proxy_server_addr = ptr->server_addr; 593 return (ptr->proxy_type); 594 } 595 } 596 ptr = ptr->next; 597 } 598 599 return (0); 600 } 601 602 void 603 ProxyModify(struct libalias *la, struct alias_link *lnk, 604 struct ip *pip, 605 int maxpacketsize, 606 int proxy_type) 607 { 608 609 LIBALIAS_LOCK_ASSERT(la); 610 (void)la; 611 612 switch (proxy_type) { 613 case PROXY_TYPE_ENCODE_IPHDR: 614 ProxyEncodeIpHeader(pip, maxpacketsize); 615 break; 616 617 case PROXY_TYPE_ENCODE_TCPSTREAM: 618 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 619 break; 620 } 621 } 622 623 624 /* 625 Public API functions 626 */ 627 628 int 629 LibAliasProxyRule(struct libalias *la, const char *cmd) 630 { 631 /* 632 * This function takes command strings of the form: 633 * 634 * server <addr>[:<port>] 635 * [port <port>] 636 * [rule n] 637 * [proto tcp|udp] 638 * [src <addr>[/n]] 639 * [dst <addr>[/n]] 640 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 641 * 642 * delete <rule number> 643 * 644 * Subfields can be in arbitrary order. Port numbers and addresses 645 * must be in either numeric or symbolic form. An optional rule number 646 * is used to control the order in which rules are searched. If two 647 * rules have the same number, then search order cannot be guaranteed, 648 * and the rules should be disjoint. If no rule number is specified, 649 * then 0 is used, and group 0 rules are always checked before any 650 * others. 651 */ 652 int i, n, len, ret; 653 int cmd_len; 654 int token_count; 655 int state; 656 char *token; 657 char buffer[256]; 658 char str_port[sizeof(buffer)]; 659 char str_server_port[sizeof(buffer)]; 660 char *res = buffer; 661 662 int rule_index; 663 int proto; 664 int proxy_type; 665 int proxy_port; 666 int server_port; 667 struct in_addr server_addr; 668 struct in_addr src_addr, src_mask; 669 struct in_addr dst_addr, dst_mask; 670 struct proxy_entry *proxy_entry; 671 672 LIBALIAS_LOCK(la); 673 ret = 0; 674 /* Copy command line into a buffer */ 675 cmd += strspn(cmd, " \t"); 676 cmd_len = strlen(cmd); 677 if (cmd_len > (int)(sizeof(buffer) - 1)) { 678 ret = -1; 679 goto getout; 680 } 681 strcpy(buffer, cmd); 682 683 /* Convert to lower case */ 684 len = strlen(buffer); 685 for (i = 0; i < len; i++) 686 buffer[i] = tolower((unsigned char)buffer[i]); 687 688 /* Set default proxy type */ 689 690 /* Set up default values */ 691 rule_index = 0; 692 proxy_type = PROXY_TYPE_ENCODE_NONE; 693 proto = IPPROTO_TCP; 694 proxy_port = 0; 695 server_addr.s_addr = 0; 696 server_port = 0; 697 src_addr.s_addr = 0; 698 IpMask(0, &src_mask); 699 dst_addr.s_addr = 0; 700 IpMask(0, &dst_mask); 701 702 str_port[0] = 0; 703 str_server_port[0] = 0; 704 705 /* Parse command string with state machine */ 706 #define STATE_READ_KEYWORD 0 707 #define STATE_READ_TYPE 1 708 #define STATE_READ_PORT 2 709 #define STATE_READ_SERVER 3 710 #define STATE_READ_RULE 4 711 #define STATE_READ_DELETE 5 712 #define STATE_READ_PROTO 6 713 #define STATE_READ_SRC 7 714 #define STATE_READ_DST 8 715 state = STATE_READ_KEYWORD; 716 token = strsep(&res, " \t"); 717 token_count = 0; 718 while (token != NULL) { 719 token_count++; 720 switch (state) { 721 case STATE_READ_KEYWORD: 722 if (strcmp(token, "type") == 0) 723 state = STATE_READ_TYPE; 724 else if (strcmp(token, "port") == 0) 725 state = STATE_READ_PORT; 726 else if (strcmp(token, "server") == 0) 727 state = STATE_READ_SERVER; 728 else if (strcmp(token, "rule") == 0) 729 state = STATE_READ_RULE; 730 else if (strcmp(token, "delete") == 0) 731 state = STATE_READ_DELETE; 732 else if (strcmp(token, "proto") == 0) 733 state = STATE_READ_PROTO; 734 else if (strcmp(token, "src") == 0) 735 state = STATE_READ_SRC; 736 else if (strcmp(token, "dst") == 0) 737 state = STATE_READ_DST; 738 else { 739 ret = -1; 740 goto getout; 741 } 742 break; 743 744 case STATE_READ_TYPE: 745 if (strcmp(token, "encode_ip_hdr") == 0) 746 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 747 else if (strcmp(token, "encode_tcp_stream") == 0) 748 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 749 else if (strcmp(token, "no_encode") == 0) 750 proxy_type = PROXY_TYPE_ENCODE_NONE; 751 else { 752 ret = -1; 753 goto getout; 754 } 755 state = STATE_READ_KEYWORD; 756 break; 757 758 case STATE_READ_PORT: 759 strcpy(str_port, token); 760 state = STATE_READ_KEYWORD; 761 break; 762 763 case STATE_READ_SERVER: 764 { 765 int err; 766 char *p; 767 char s[sizeof(buffer)]; 768 769 p = token; 770 while (*p != ':' && *p != 0) 771 p++; 772 773 if (*p != ':') { 774 err = IpAddr(token, &server_addr); 775 if (err) { 776 ret = -1; 777 goto getout; 778 } 779 } else { 780 *p = ' '; 781 782 n = sscanf(token, "%s %s", s, str_server_port); 783 if (n != 2) { 784 ret = -1; 785 goto getout; 786 } 787 788 err = IpAddr(s, &server_addr); 789 if (err) { 790 ret = -1; 791 goto getout; 792 } 793 } 794 } 795 state = STATE_READ_KEYWORD; 796 break; 797 798 case STATE_READ_RULE: 799 n = sscanf(token, "%d", &rule_index); 800 if (n != 1 || rule_index < 0) { 801 ret = -1; 802 goto getout; 803 } 804 state = STATE_READ_KEYWORD; 805 break; 806 807 case STATE_READ_DELETE: 808 { 809 int err; 810 int rule_to_delete; 811 812 if (token_count != 2) { 813 ret = -1; 814 goto getout; 815 } 816 817 n = sscanf(token, "%d", &rule_to_delete); 818 if (n != 1) { 819 ret = -1; 820 goto getout; 821 } 822 err = RuleNumberDelete(la, rule_to_delete); 823 if (err) 824 ret = -1; 825 ret = 0; 826 goto getout; 827 } 828 829 case STATE_READ_PROTO: 830 if (strcmp(token, "tcp") == 0) 831 proto = IPPROTO_TCP; 832 else if (strcmp(token, "udp") == 0) 833 proto = IPPROTO_UDP; 834 else { 835 ret = -1; 836 goto getout; 837 } 838 state = STATE_READ_KEYWORD; 839 break; 840 841 case STATE_READ_SRC: 842 case STATE_READ_DST: 843 { 844 int err; 845 char *p; 846 struct in_addr mask; 847 struct in_addr addr; 848 849 p = token; 850 while (*p != '/' && *p != 0) 851 p++; 852 853 if (*p != '/') { 854 IpMask(32, &mask); 855 err = IpAddr(token, &addr); 856 if (err) { 857 ret = -1; 858 goto getout; 859 } 860 } else { 861 int nbits; 862 char s[sizeof(buffer)]; 863 864 *p = ' '; 865 n = sscanf(token, "%s %d", s, &nbits); 866 if (n != 2) { 867 ret = -1; 868 goto getout; 869 } 870 871 err = IpAddr(s, &addr); 872 if (err) { 873 ret = -1; 874 goto getout; 875 } 876 877 err = IpMask(nbits, &mask); 878 if (err) { 879 ret = -1; 880 goto getout; 881 } 882 } 883 884 if (state == STATE_READ_SRC) { 885 src_addr = addr; 886 src_mask = mask; 887 } else { 888 dst_addr = addr; 889 dst_mask = mask; 890 } 891 } 892 state = STATE_READ_KEYWORD; 893 break; 894 895 default: 896 ret = -1; 897 goto getout; 898 break; 899 } 900 901 do { 902 token = strsep(&res, " \t"); 903 } while (token != NULL && !*token); 904 } 905 #undef STATE_READ_KEYWORD 906 #undef STATE_READ_TYPE 907 #undef STATE_READ_PORT 908 #undef STATE_READ_SERVER 909 #undef STATE_READ_RULE 910 #undef STATE_READ_DELETE 911 #undef STATE_READ_PROTO 912 #undef STATE_READ_SRC 913 #undef STATE_READ_DST 914 915 /* Convert port strings to numbers. This needs to be done after 916 the string is parsed, because the prototype might not be designated 917 before the ports (which might be symbolic entries in /etc/services) */ 918 919 if (strlen(str_port) != 0) { 920 int err; 921 922 err = IpPort(str_port, proto, &proxy_port); 923 if (err) { 924 ret = -1; 925 goto getout; 926 } 927 } else { 928 proxy_port = 0; 929 } 930 931 if (strlen(str_server_port) != 0) { 932 int err; 933 934 err = IpPort(str_server_port, proto, &server_port); 935 if (err) { 936 ret = -1; 937 goto getout; 938 } 939 } else { 940 server_port = 0; 941 } 942 943 /* Check that at least the server address has been defined */ 944 if (server_addr.s_addr == 0) { 945 ret = -1; 946 goto getout; 947 } 948 949 /* Add to linked list */ 950 proxy_entry = malloc(sizeof(struct proxy_entry)); 951 if (proxy_entry == NULL) { 952 ret = -1; 953 goto getout; 954 } 955 956 proxy_entry->proxy_type = proxy_type; 957 proxy_entry->rule_index = rule_index; 958 proxy_entry->proto = proto; 959 proxy_entry->proxy_port = htons(proxy_port); 960 proxy_entry->server_port = htons(server_port); 961 proxy_entry->server_addr = server_addr; 962 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 963 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 964 proxy_entry->src_mask = src_mask; 965 proxy_entry->dst_mask = dst_mask; 966 967 RuleAdd(la, proxy_entry); 968 969 getout: 970 LIBALIAS_UNLOCK(la); 971 return (ret); 972 } 973