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) 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 if (la->proxyList == NULL) { 316 la->proxyList = entry; 317 entry->last = NULL; 318 entry->next = NULL; 319 return; 320 } 321 entry->la = la; 322 323 rule_index = entry->rule_index; 324 ptr = la->proxyList; 325 ptr_last = NULL; 326 while (ptr != NULL) { 327 if (ptr->rule_index >= rule_index) { 328 if (ptr_last == NULL) { 329 entry->next = la->proxyList; 330 entry->last = NULL; 331 la->proxyList->last = entry; 332 la->proxyList = entry; 333 return; 334 } 335 ptr_last->next = entry; 336 ptr->last = entry; 337 entry->last = ptr->last; 338 entry->next = ptr; 339 return; 340 } 341 ptr_last = ptr; 342 ptr = ptr->next; 343 } 344 345 ptr_last->next = entry; 346 entry->last = ptr_last; 347 entry->next = NULL; 348 } 349 350 static void 351 RuleDelete(struct proxy_entry *entry) 352 { 353 struct libalias *la; 354 355 la = entry->la; 356 if (entry->last != NULL) 357 entry->last->next = entry->next; 358 else 359 la->proxyList = entry->next; 360 361 if (entry->next != NULL) 362 entry->next->last = entry->last; 363 364 free(entry); 365 } 366 367 static int 368 RuleNumberDelete(struct libalias *la, int rule_index) 369 { 370 int err; 371 struct proxy_entry *ptr; 372 373 err = -1; 374 ptr = la->proxyList; 375 while (ptr != NULL) { 376 struct proxy_entry *ptr_next; 377 378 ptr_next = ptr->next; 379 if (ptr->rule_index == rule_index) { 380 err = 0; 381 RuleDelete(ptr); 382 } 383 ptr = ptr_next; 384 } 385 386 return (err); 387 } 388 389 static void 390 ProxyEncodeTcpStream(struct alias_link *lnk, 391 struct ip *pip, 392 int maxpacketsize) 393 { 394 int slen; 395 char buffer[40]; 396 struct tcphdr *tc; 397 398 /* Compute pointer to tcp header */ 399 tc = (struct tcphdr *)ip_next(pip); 400 401 /* Don't modify if once already modified */ 402 403 if (GetAckModified(lnk)) 404 return; 405 406 /* Translate destination address and port to string form */ 407 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 408 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 409 410 /* Pad string out to a multiple of two in length */ 411 slen = strlen(buffer); 412 switch (slen % 2) { 413 case 0: 414 strcat(buffer, " \n"); 415 slen += 2; 416 break; 417 case 1: 418 strcat(buffer, "\n"); 419 slen += 1; 420 } 421 422 /* Check for packet overflow */ 423 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 424 return; 425 426 /* Shift existing TCP data and insert destination string */ 427 { 428 int dlen; 429 int hlen; 430 u_char *p; 431 432 hlen = (pip->ip_hl + tc->th_off) << 2; 433 dlen = ntohs(pip->ip_len) - hlen; 434 435 /* Modify first packet that has data in it */ 436 437 if (dlen == 0) 438 return; 439 440 p = (char *)pip; 441 p += hlen; 442 443 bcopy(p, p + slen, dlen); 444 memcpy(p, buffer, slen); 445 } 446 447 /* Save information about modfied sequence number */ 448 { 449 int delta; 450 451 SetAckModified(lnk); 452 delta = GetDeltaSeqOut(pip, lnk); 453 AddSeq(pip, lnk, delta + slen); 454 } 455 456 /* Update IP header packet length and checksum */ 457 { 458 int accumulate; 459 460 accumulate = pip->ip_len; 461 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 462 accumulate -= pip->ip_len; 463 464 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 465 } 466 467 /* Update TCP checksum, Use TcpChecksum since so many things have 468 already changed. */ 469 470 tc->th_sum = 0; 471 #ifdef _KERNEL 472 tc->th_x2 = 1; 473 #else 474 tc->th_sum = TcpChecksum(pip); 475 #endif 476 } 477 478 static void 479 ProxyEncodeIpHeader(struct ip *pip, 480 int maxpacketsize) 481 { 482 #define OPTION_LEN_BYTES 8 483 #define OPTION_LEN_INT16 4 484 #define OPTION_LEN_INT32 2 485 u_char option[OPTION_LEN_BYTES]; 486 487 #ifdef LIBALIAS_DEBUG 488 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 489 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 490 #endif 491 492 (void)maxpacketsize; 493 494 /* Check to see that there is room to add an IP option */ 495 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 496 return; 497 498 /* Build option and copy into packet */ 499 { 500 u_char *ptr; 501 struct tcphdr *tc; 502 503 ptr = (u_char *) pip; 504 ptr += 20; 505 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 506 507 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 508 option[1] = OPTION_LEN_BYTES; 509 510 memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 511 512 tc = (struct tcphdr *)ip_next(pip); 513 memcpy(&option[6], (u_char *) & tc->th_sport, 2); 514 515 memcpy(ptr, option, 8); 516 } 517 518 /* Update checksum, header length and packet length */ 519 { 520 int i; 521 int accumulate; 522 u_short *sptr; 523 524 sptr = (u_short *) option; 525 accumulate = 0; 526 for (i = 0; i < OPTION_LEN_INT16; i++) 527 accumulate -= *(sptr++); 528 529 sptr = (u_short *) pip; 530 accumulate += *sptr; 531 pip->ip_hl += OPTION_LEN_INT32; 532 accumulate -= *sptr; 533 534 accumulate += pip->ip_len; 535 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 536 accumulate -= pip->ip_len; 537 538 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 539 } 540 #undef OPTION_LEN_BYTES 541 #undef OPTION_LEN_INT16 542 #undef OPTION_LEN_INT32 543 #ifdef LIBALIAS_DEBUG 544 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 545 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 546 #endif 547 } 548 549 550 /* Functions by other packet alias source files 551 552 ProxyCheck() -- Checks whether an outgoing packet should 553 be proxied. 554 ProxyModify() -- Encodes the original destination address/port 555 for a packet which is to be redirected to 556 a proxy server. 557 */ 558 559 int 560 ProxyCheck(struct libalias *la, struct ip *pip, 561 struct in_addr *proxy_server_addr, 562 u_short * proxy_server_port) 563 { 564 u_short dst_port; 565 struct in_addr src_addr; 566 struct in_addr dst_addr; 567 struct proxy_entry *ptr; 568 569 src_addr = pip->ip_src; 570 dst_addr = pip->ip_dst; 571 dst_port = ((struct tcphdr *)ip_next(pip)) 572 ->th_dport; 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 && pip->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 (void)la; 610 611 switch (proxy_type) { 612 case PROXY_TYPE_ENCODE_IPHDR: 613 ProxyEncodeIpHeader(pip, maxpacketsize); 614 break; 615 616 case PROXY_TYPE_ENCODE_TCPSTREAM: 617 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 618 break; 619 } 620 } 621 622 623 /* 624 Public API functions 625 */ 626 627 int 628 LibAliasProxyRule(struct libalias *la, const char *cmd) 629 { 630 /* 631 * This function takes command strings of the form: 632 * 633 * server <addr>[:<port>] 634 * [port <port>] 635 * [rule n] 636 * [proto tcp|udp] 637 * [src <addr>[/n]] 638 * [dst <addr>[/n]] 639 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 640 * 641 * delete <rule number> 642 * 643 * Subfields can be in arbitrary order. Port numbers and addresses 644 * must be in either numeric or symbolic form. An optional rule number 645 * is used to control the order in which rules are searched. If two 646 * rules have the same number, then search order cannot be guaranteed, 647 * and the rules should be disjoint. If no rule number is specified, 648 * then 0 is used, and group 0 rules are always checked before any 649 * others. 650 */ 651 int i, n, len; 652 int cmd_len; 653 int token_count; 654 int state; 655 char *token; 656 char buffer[256]; 657 char str_port[sizeof(buffer)]; 658 char str_server_port[sizeof(buffer)]; 659 char *res = buffer; 660 661 int rule_index; 662 int proto; 663 int proxy_type; 664 int proxy_port; 665 int server_port; 666 struct in_addr server_addr; 667 struct in_addr src_addr, src_mask; 668 struct in_addr dst_addr, dst_mask; 669 struct proxy_entry *proxy_entry; 670 671 /* Copy command line into a buffer */ 672 cmd += strspn(cmd, " \t"); 673 cmd_len = strlen(cmd); 674 if (cmd_len > (int)(sizeof(buffer) - 1)) 675 return (-1); 676 strcpy(buffer, cmd); 677 678 /* Convert to lower case */ 679 len = strlen(buffer); 680 for (i = 0; i < len; i++) 681 buffer[i] = tolower((unsigned char)buffer[i]); 682 683 /* Set default proxy type */ 684 685 /* Set up default values */ 686 rule_index = 0; 687 proxy_type = PROXY_TYPE_ENCODE_NONE; 688 proto = IPPROTO_TCP; 689 proxy_port = 0; 690 server_addr.s_addr = 0; 691 server_port = 0; 692 src_addr.s_addr = 0; 693 IpMask(0, &src_mask); 694 dst_addr.s_addr = 0; 695 IpMask(0, &dst_mask); 696 697 str_port[0] = 0; 698 str_server_port[0] = 0; 699 700 /* Parse command string with state machine */ 701 #define STATE_READ_KEYWORD 0 702 #define STATE_READ_TYPE 1 703 #define STATE_READ_PORT 2 704 #define STATE_READ_SERVER 3 705 #define STATE_READ_RULE 4 706 #define STATE_READ_DELETE 5 707 #define STATE_READ_PROTO 6 708 #define STATE_READ_SRC 7 709 #define STATE_READ_DST 8 710 state = STATE_READ_KEYWORD; 711 token = strsep(&res, " \t"); 712 token_count = 0; 713 while (token != NULL) { 714 token_count++; 715 switch (state) { 716 case STATE_READ_KEYWORD: 717 if (strcmp(token, "type") == 0) 718 state = STATE_READ_TYPE; 719 else if (strcmp(token, "port") == 0) 720 state = STATE_READ_PORT; 721 else if (strcmp(token, "server") == 0) 722 state = STATE_READ_SERVER; 723 else if (strcmp(token, "rule") == 0) 724 state = STATE_READ_RULE; 725 else if (strcmp(token, "delete") == 0) 726 state = STATE_READ_DELETE; 727 else if (strcmp(token, "proto") == 0) 728 state = STATE_READ_PROTO; 729 else if (strcmp(token, "src") == 0) 730 state = STATE_READ_SRC; 731 else if (strcmp(token, "dst") == 0) 732 state = STATE_READ_DST; 733 else 734 return (-1); 735 break; 736 737 case STATE_READ_TYPE: 738 if (strcmp(token, "encode_ip_hdr") == 0) 739 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 740 else if (strcmp(token, "encode_tcp_stream") == 0) 741 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 742 else if (strcmp(token, "no_encode") == 0) 743 proxy_type = PROXY_TYPE_ENCODE_NONE; 744 else 745 return (-1); 746 state = STATE_READ_KEYWORD; 747 break; 748 749 case STATE_READ_PORT: 750 strcpy(str_port, token); 751 state = STATE_READ_KEYWORD; 752 break; 753 754 case STATE_READ_SERVER: 755 { 756 int err; 757 char *p; 758 char s[sizeof(buffer)]; 759 760 p = token; 761 while (*p != ':' && *p != 0) 762 p++; 763 764 if (*p != ':') { 765 err = IpAddr(token, &server_addr); 766 if (err) 767 return (-1); 768 } else { 769 *p = ' '; 770 771 n = sscanf(token, "%s %s", s, str_server_port); 772 if (n != 2) 773 return (-1); 774 775 err = IpAddr(s, &server_addr); 776 if (err) 777 return (-1); 778 } 779 } 780 state = STATE_READ_KEYWORD; 781 break; 782 783 case STATE_READ_RULE: 784 n = sscanf(token, "%d", &rule_index); 785 if (n != 1 || rule_index < 0) 786 return (-1); 787 state = STATE_READ_KEYWORD; 788 break; 789 790 case STATE_READ_DELETE: 791 { 792 int err; 793 int rule_to_delete; 794 795 if (token_count != 2) 796 return (-1); 797 798 n = sscanf(token, "%d", &rule_to_delete); 799 if (n != 1) 800 return (-1); 801 err = RuleNumberDelete(la, rule_to_delete); 802 if (err) 803 return (-1); 804 return (0); 805 } 806 807 case STATE_READ_PROTO: 808 if (strcmp(token, "tcp") == 0) 809 proto = IPPROTO_TCP; 810 else if (strcmp(token, "udp") == 0) 811 proto = IPPROTO_UDP; 812 else 813 return (-1); 814 state = STATE_READ_KEYWORD; 815 break; 816 817 case STATE_READ_SRC: 818 case STATE_READ_DST: 819 { 820 int err; 821 char *p; 822 struct in_addr mask; 823 struct in_addr addr; 824 825 p = token; 826 while (*p != '/' && *p != 0) 827 p++; 828 829 if (*p != '/') { 830 IpMask(32, &mask); 831 err = IpAddr(token, &addr); 832 if (err) 833 return (-1); 834 } else { 835 int nbits; 836 char s[sizeof(buffer)]; 837 838 *p = ' '; 839 n = sscanf(token, "%s %d", s, &nbits); 840 if (n != 2) 841 return (-1); 842 843 err = IpAddr(s, &addr); 844 if (err) 845 return (-1); 846 847 err = IpMask(nbits, &mask); 848 if (err) 849 return (-1); 850 } 851 852 if (state == STATE_READ_SRC) { 853 src_addr = addr; 854 src_mask = mask; 855 } else { 856 dst_addr = addr; 857 dst_mask = mask; 858 } 859 } 860 state = STATE_READ_KEYWORD; 861 break; 862 863 default: 864 return (-1); 865 break; 866 } 867 868 do { 869 token = strsep(&res, " \t"); 870 } while (token != NULL && !*token); 871 } 872 #undef STATE_READ_KEYWORD 873 #undef STATE_READ_TYPE 874 #undef STATE_READ_PORT 875 #undef STATE_READ_SERVER 876 #undef STATE_READ_RULE 877 #undef STATE_READ_DELETE 878 #undef STATE_READ_PROTO 879 #undef STATE_READ_SRC 880 #undef STATE_READ_DST 881 882 /* Convert port strings to numbers. This needs to be done after 883 the string is parsed, because the prototype might not be designated 884 before the ports (which might be symbolic entries in /etc/services) */ 885 886 if (strlen(str_port) != 0) { 887 int err; 888 889 err = IpPort(str_port, proto, &proxy_port); 890 if (err) 891 return (-1); 892 } else { 893 proxy_port = 0; 894 } 895 896 if (strlen(str_server_port) != 0) { 897 int err; 898 899 err = IpPort(str_server_port, proto, &server_port); 900 if (err) 901 return (-1); 902 } else { 903 server_port = 0; 904 } 905 906 /* Check that at least the server address has been defined */ 907 if (server_addr.s_addr == 0) 908 return (-1); 909 910 /* Add to linked list */ 911 proxy_entry = malloc(sizeof(struct proxy_entry)); 912 if (proxy_entry == NULL) 913 return (-1); 914 915 proxy_entry->proxy_type = proxy_type; 916 proxy_entry->rule_index = rule_index; 917 proxy_entry->proto = proto; 918 proxy_entry->proxy_port = htons(proxy_port); 919 proxy_entry->server_port = htons(server_port); 920 proxy_entry->server_addr = server_addr; 921 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 922 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 923 proxy_entry->src_mask = src_mask; 924 proxy_entry->dst_mask = dst_mask; 925 926 RuleAdd(la, proxy_entry); 927 928 return (0); 929 } 930