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/kernel.h> 62 #include <sys/malloc.h> 63 #include <sys/limits.h> 64 #else 65 #include <sys/types.h> 66 #include <sys/socket.h> 67 #include <ctype.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <string.h> 71 #include <netdb.h> 72 #include <arpa/inet.h> 73 #endif 74 75 /* BSD IPV4 includes */ 76 #include <netinet/in_systm.h> 77 #include <netinet/in.h> 78 #include <netinet/ip.h> 79 #include <netinet/tcp.h> 80 81 #ifdef _KERNEL 82 #include <netinet/libalias/alias.h> 83 #include <netinet/libalias/alias_local.h> 84 #else 85 #include "alias.h" /* Public API functions for libalias */ 86 #include "alias_local.h" /* Functions used by alias*.c */ 87 #endif 88 89 /* 90 Data structures 91 */ 92 93 /* 94 * A linked list of arbitrary length, based on struct proxy_entry is 95 * used to store proxy rules. 96 */ 97 struct proxy_entry { 98 struct libalias *la; 99 #define PROXY_TYPE_ENCODE_NONE 1 100 #define PROXY_TYPE_ENCODE_TCPSTREAM 2 101 #define PROXY_TYPE_ENCODE_IPHDR 3 102 int rule_index; 103 int proxy_type; 104 u_char proto; 105 u_short proxy_port; 106 u_short server_port; 107 108 struct in_addr server_addr; 109 110 struct in_addr src_addr; 111 struct in_addr src_mask; 112 113 struct in_addr dst_addr; 114 struct in_addr dst_mask; 115 116 struct proxy_entry *next; 117 struct proxy_entry *last; 118 }; 119 120 121 122 /* 123 File scope variables 124 */ 125 126 127 128 /* Local (static) functions: 129 130 IpMask() -- Utility function for creating IP 131 masks from integer (1-32) specification. 132 IpAddr() -- Utility function for converting string 133 to IP address 134 IpPort() -- Utility function for converting string 135 to port number 136 RuleAdd() -- Adds an element to the rule list. 137 RuleDelete() -- Removes an element from the rule list. 138 RuleNumberDelete() -- Removes all elements from the rule list 139 having a certain rule number. 140 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 141 of a TCP stream. 142 ProxyEncodeIpHeader() -- Adds an IP option indicating the true 143 destination of a proxied IP packet 144 */ 145 146 #ifdef _KERNEL /* XXX: can it be moved to libkern? */ 147 static int inet_aton(const char *cp, struct in_addr *addr); 148 #endif 149 static int IpMask(int, struct in_addr *); 150 static int IpAddr(char *, struct in_addr *); 151 static int IpPort(char *, int, int *); 152 static void RuleAdd(struct libalias *la, struct proxy_entry *); 153 static void RuleDelete(struct proxy_entry *); 154 static int RuleNumberDelete(struct libalias *la, int); 155 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 156 static void ProxyEncodeIpHeader(struct ip *, int); 157 158 #ifdef _KERNEL 159 static int 160 inet_aton(cp, addr) 161 const char *cp; 162 struct in_addr *addr; 163 { 164 u_long parts[4]; 165 in_addr_t val; 166 const char *c; 167 char *endptr; 168 int gotend, n; 169 170 c = (const char *)cp; 171 n = 0; 172 /* 173 * Run through the string, grabbing numbers until 174 * the end of the string, or some error 175 */ 176 gotend = 0; 177 while (!gotend) { 178 unsigned long l; 179 180 l = strtoul(c, &endptr, 0); 181 182 if (l == ULONG_MAX || l == 0) 183 return (0); 184 185 val = (in_addr_t)l; 186 /* 187 * If the whole string is invalid, endptr will equal 188 * c.. this way we can make sure someone hasn't 189 * gone '.12' or something which would get past 190 * the next check. 191 */ 192 if (endptr == c) 193 return (0); 194 parts[n] = val; 195 c = endptr; 196 197 /* Check the next character past the previous number's end */ 198 switch (*c) { 199 case '.' : 200 /* Make sure we only do 3 dots .. */ 201 if (n == 3) /* Whoops. Quit. */ 202 return (0); 203 n++; 204 c++; 205 break; 206 207 case '\0': 208 gotend = 1; 209 break; 210 211 default: 212 if (isspace((unsigned char)*c)) { 213 gotend = 1; 214 break; 215 } else 216 return (0); /* Invalid character, so fail */ 217 } 218 219 } 220 221 /* 222 * Concoct the address according to 223 * the number of parts specified. 224 */ 225 226 switch (n) { 227 case 0: /* a -- 32 bits */ 228 /* 229 * Nothing is necessary here. Overflow checking was 230 * already done in strtoul(). 231 */ 232 break; 233 case 1: /* a.b -- 8.24 bits */ 234 if (val > 0xffffff || parts[0] > 0xff) 235 return (0); 236 val |= parts[0] << 24; 237 break; 238 239 case 2: /* a.b.c -- 8.8.16 bits */ 240 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) 241 return (0); 242 val |= (parts[0] << 24) | (parts[1] << 16); 243 break; 244 245 case 3: /* a.b.c.d -- 8.8.8.8 bits */ 246 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || 247 parts[2] > 0xff) 248 return (0); 249 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 250 break; 251 } 252 253 if (addr != NULL) 254 addr->s_addr = htonl(val); 255 return (1); 256 } 257 #endif 258 259 static int 260 IpMask(int nbits, struct in_addr *mask) 261 { 262 int i; 263 u_int imask; 264 265 if (nbits < 0 || nbits > 32) 266 return (-1); 267 268 imask = 0; 269 for (i = 0; i < nbits; i++) 270 imask = (imask >> 1) + 0x80000000; 271 mask->s_addr = htonl(imask); 272 273 return (0); 274 } 275 276 static int 277 IpAddr(char *s, struct in_addr *addr) 278 { 279 if (inet_aton(s, addr) == 0) 280 return (-1); 281 else 282 return (0); 283 } 284 285 static int 286 IpPort(char *s, int proto, int *port) 287 { 288 int n; 289 290 n = sscanf(s, "%d", port); 291 if (n != 1) 292 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */ 293 { 294 struct servent *se; 295 296 if (proto == IPPROTO_TCP) 297 se = getservbyname(s, "tcp"); 298 else if (proto == IPPROTO_UDP) 299 se = getservbyname(s, "udp"); 300 else 301 return (-1); 302 303 if (se == NULL) 304 return (-1); 305 306 *port = (u_int) ntohs(se->s_port); 307 } 308 #else 309 return (-1); 310 #endif 311 return (0); 312 } 313 314 void 315 RuleAdd(struct libalias *la, struct proxy_entry *entry) 316 { 317 int rule_index; 318 struct proxy_entry *ptr; 319 struct proxy_entry *ptr_last; 320 321 if (la->proxyList == NULL) { 322 la->proxyList = entry; 323 entry->last = NULL; 324 entry->next = NULL; 325 return; 326 } 327 entry->la = la; 328 329 rule_index = entry->rule_index; 330 ptr = la->proxyList; 331 ptr_last = NULL; 332 while (ptr != NULL) { 333 if (ptr->rule_index >= rule_index) { 334 if (ptr_last == NULL) { 335 entry->next = la->proxyList; 336 entry->last = NULL; 337 la->proxyList->last = entry; 338 la->proxyList = entry; 339 return; 340 } 341 ptr_last->next = entry; 342 ptr->last = entry; 343 entry->last = ptr->last; 344 entry->next = ptr; 345 return; 346 } 347 ptr_last = ptr; 348 ptr = ptr->next; 349 } 350 351 ptr_last->next = entry; 352 entry->last = ptr_last; 353 entry->next = NULL; 354 } 355 356 static void 357 RuleDelete(struct proxy_entry *entry) 358 { 359 struct libalias *la; 360 361 la = entry->la; 362 if (entry->last != NULL) 363 entry->last->next = entry->next; 364 else 365 la->proxyList = entry->next; 366 367 if (entry->next != NULL) 368 entry->next->last = entry->last; 369 370 free(entry); 371 } 372 373 static int 374 RuleNumberDelete(struct libalias *la, int rule_index) 375 { 376 int err; 377 struct proxy_entry *ptr; 378 379 err = -1; 380 ptr = la->proxyList; 381 while (ptr != NULL) { 382 struct proxy_entry *ptr_next; 383 384 ptr_next = ptr->next; 385 if (ptr->rule_index == rule_index) { 386 err = 0; 387 RuleDelete(ptr); 388 } 389 ptr = ptr_next; 390 } 391 392 return (err); 393 } 394 395 static void 396 ProxyEncodeTcpStream(struct alias_link *lnk, 397 struct ip *pip, 398 int maxpacketsize) 399 { 400 int slen; 401 char buffer[40]; 402 struct tcphdr *tc; 403 404 /* Compute pointer to tcp header */ 405 tc = (struct tcphdr *)ip_next(pip); 406 407 /* Don't modify if once already modified */ 408 409 if (GetAckModified(lnk)) 410 return; 411 412 /* Translate destination address and port to string form */ 413 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 414 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 415 416 /* Pad string out to a multiple of two in length */ 417 slen = strlen(buffer); 418 switch (slen % 2) { 419 case 0: 420 strcat(buffer, " \n"); 421 slen += 2; 422 break; 423 case 1: 424 strcat(buffer, "\n"); 425 slen += 1; 426 } 427 428 /* Check for packet overflow */ 429 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 430 return; 431 432 /* Shift existing TCP data and insert destination string */ 433 { 434 int dlen; 435 int hlen; 436 u_char *p; 437 438 hlen = (pip->ip_hl + tc->th_off) << 2; 439 dlen = ntohs(pip->ip_len) - hlen; 440 441 /* Modify first packet that has data in it */ 442 443 if (dlen == 0) 444 return; 445 446 p = (char *)pip; 447 p += hlen; 448 449 bcopy(p, p + slen, dlen); 450 memcpy(p, buffer, slen); 451 } 452 453 /* Save information about modfied sequence number */ 454 { 455 int delta; 456 457 SetAckModified(lnk); 458 delta = GetDeltaSeqOut(pip, lnk); 459 AddSeq(pip, lnk, delta + slen); 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 ip *pip, 567 struct in_addr *proxy_server_addr, 568 u_short * proxy_server_port) 569 { 570 u_short dst_port; 571 struct in_addr src_addr; 572 struct in_addr dst_addr; 573 struct proxy_entry *ptr; 574 575 src_addr = pip->ip_src; 576 dst_addr = pip->ip_dst; 577 dst_port = ((struct tcphdr *)ip_next(pip)) 578 ->th_dport; 579 580 ptr = la->proxyList; 581 while (ptr != NULL) { 582 u_short proxy_port; 583 584 proxy_port = ptr->proxy_port; 585 if ((dst_port == proxy_port || proxy_port == 0) 586 && pip->ip_p == ptr->proto 587 && src_addr.s_addr != ptr->server_addr.s_addr) { 588 struct in_addr src_addr_masked; 589 struct in_addr dst_addr_masked; 590 591 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 592 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 593 594 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 595 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 596 if ((*proxy_server_port = ptr->server_port) == 0) 597 *proxy_server_port = dst_port; 598 *proxy_server_addr = ptr->server_addr; 599 return (ptr->proxy_type); 600 } 601 } 602 ptr = ptr->next; 603 } 604 605 return (0); 606 } 607 608 void 609 ProxyModify(struct libalias *la, struct alias_link *lnk, 610 struct ip *pip, 611 int maxpacketsize, 612 int proxy_type) 613 { 614 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; 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 /* Copy command line into a buffer */ 678 cmd += strspn(cmd, " \t"); 679 cmd_len = strlen(cmd); 680 if (cmd_len > (int)(sizeof(buffer) - 1)) 681 return (-1); 682 strcpy(buffer, cmd); 683 684 /* Convert to lower case */ 685 len = strlen(buffer); 686 for (i = 0; i < len; i++) 687 buffer[i] = tolower((unsigned char)buffer[i]); 688 689 /* Set default proxy type */ 690 691 /* Set up default values */ 692 rule_index = 0; 693 proxy_type = PROXY_TYPE_ENCODE_NONE; 694 proto = IPPROTO_TCP; 695 proxy_port = 0; 696 server_addr.s_addr = 0; 697 server_port = 0; 698 src_addr.s_addr = 0; 699 IpMask(0, &src_mask); 700 dst_addr.s_addr = 0; 701 IpMask(0, &dst_mask); 702 703 str_port[0] = 0; 704 str_server_port[0] = 0; 705 706 /* Parse command string with state machine */ 707 #define STATE_READ_KEYWORD 0 708 #define STATE_READ_TYPE 1 709 #define STATE_READ_PORT 2 710 #define STATE_READ_SERVER 3 711 #define STATE_READ_RULE 4 712 #define STATE_READ_DELETE 5 713 #define STATE_READ_PROTO 6 714 #define STATE_READ_SRC 7 715 #define STATE_READ_DST 8 716 state = STATE_READ_KEYWORD; 717 token = strsep(&res, " \t"); 718 token_count = 0; 719 while (token != NULL) { 720 token_count++; 721 switch (state) { 722 case STATE_READ_KEYWORD: 723 if (strcmp(token, "type") == 0) 724 state = STATE_READ_TYPE; 725 else if (strcmp(token, "port") == 0) 726 state = STATE_READ_PORT; 727 else if (strcmp(token, "server") == 0) 728 state = STATE_READ_SERVER; 729 else if (strcmp(token, "rule") == 0) 730 state = STATE_READ_RULE; 731 else if (strcmp(token, "delete") == 0) 732 state = STATE_READ_DELETE; 733 else if (strcmp(token, "proto") == 0) 734 state = STATE_READ_PROTO; 735 else if (strcmp(token, "src") == 0) 736 state = STATE_READ_SRC; 737 else if (strcmp(token, "dst") == 0) 738 state = STATE_READ_DST; 739 else 740 return (-1); 741 break; 742 743 case STATE_READ_TYPE: 744 if (strcmp(token, "encode_ip_hdr") == 0) 745 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 746 else if (strcmp(token, "encode_tcp_stream") == 0) 747 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 748 else if (strcmp(token, "no_encode") == 0) 749 proxy_type = PROXY_TYPE_ENCODE_NONE; 750 else 751 return (-1); 752 state = STATE_READ_KEYWORD; 753 break; 754 755 case STATE_READ_PORT: 756 strcpy(str_port, token); 757 state = STATE_READ_KEYWORD; 758 break; 759 760 case STATE_READ_SERVER: 761 { 762 int err; 763 char *p; 764 char s[sizeof(buffer)]; 765 766 p = token; 767 while (*p != ':' && *p != 0) 768 p++; 769 770 if (*p != ':') { 771 err = IpAddr(token, &server_addr); 772 if (err) 773 return (-1); 774 } else { 775 *p = ' '; 776 777 n = sscanf(token, "%s %s", s, str_server_port); 778 if (n != 2) 779 return (-1); 780 781 err = IpAddr(s, &server_addr); 782 if (err) 783 return (-1); 784 } 785 } 786 state = STATE_READ_KEYWORD; 787 break; 788 789 case STATE_READ_RULE: 790 n = sscanf(token, "%d", &rule_index); 791 if (n != 1 || rule_index < 0) 792 return (-1); 793 state = STATE_READ_KEYWORD; 794 break; 795 796 case STATE_READ_DELETE: 797 { 798 int err; 799 int rule_to_delete; 800 801 if (token_count != 2) 802 return (-1); 803 804 n = sscanf(token, "%d", &rule_to_delete); 805 if (n != 1) 806 return (-1); 807 err = RuleNumberDelete(la, rule_to_delete); 808 if (err) 809 return (-1); 810 return (0); 811 } 812 813 case STATE_READ_PROTO: 814 if (strcmp(token, "tcp") == 0) 815 proto = IPPROTO_TCP; 816 else if (strcmp(token, "udp") == 0) 817 proto = IPPROTO_UDP; 818 else 819 return (-1); 820 state = STATE_READ_KEYWORD; 821 break; 822 823 case STATE_READ_SRC: 824 case STATE_READ_DST: 825 { 826 int err; 827 char *p; 828 struct in_addr mask; 829 struct in_addr addr; 830 831 p = token; 832 while (*p != '/' && *p != 0) 833 p++; 834 835 if (*p != '/') { 836 IpMask(32, &mask); 837 err = IpAddr(token, &addr); 838 if (err) 839 return (-1); 840 } else { 841 int nbits; 842 char s[sizeof(buffer)]; 843 844 *p = ' '; 845 n = sscanf(token, "%s %d", s, &nbits); 846 if (n != 2) 847 return (-1); 848 849 err = IpAddr(s, &addr); 850 if (err) 851 return (-1); 852 853 err = IpMask(nbits, &mask); 854 if (err) 855 return (-1); 856 } 857 858 if (state == STATE_READ_SRC) { 859 src_addr = addr; 860 src_mask = mask; 861 } else { 862 dst_addr = addr; 863 dst_mask = mask; 864 } 865 } 866 state = STATE_READ_KEYWORD; 867 break; 868 869 default: 870 return (-1); 871 break; 872 } 873 874 do { 875 token = strsep(&res, " \t"); 876 } while (token != NULL && !*token); 877 } 878 #undef STATE_READ_KEYWORD 879 #undef STATE_READ_TYPE 880 #undef STATE_READ_PORT 881 #undef STATE_READ_SERVER 882 #undef STATE_READ_RULE 883 #undef STATE_READ_DELETE 884 #undef STATE_READ_PROTO 885 #undef STATE_READ_SRC 886 #undef STATE_READ_DST 887 888 /* Convert port strings to numbers. This needs to be done after 889 the string is parsed, because the prototype might not be designated 890 before the ports (which might be symbolic entries in /etc/services) */ 891 892 if (strlen(str_port) != 0) { 893 int err; 894 895 err = IpPort(str_port, proto, &proxy_port); 896 if (err) 897 return (-1); 898 } else { 899 proxy_port = 0; 900 } 901 902 if (strlen(str_server_port) != 0) { 903 int err; 904 905 err = IpPort(str_server_port, proto, &server_port); 906 if (err) 907 return (-1); 908 } else { 909 server_port = 0; 910 } 911 912 /* Check that at least the server address has been defined */ 913 if (server_addr.s_addr == 0) 914 return (-1); 915 916 /* Add to linked list */ 917 proxy_entry = malloc(sizeof(struct proxy_entry)); 918 if (proxy_entry == NULL) 919 return (-1); 920 921 proxy_entry->proxy_type = proxy_type; 922 proxy_entry->rule_index = rule_index; 923 proxy_entry->proto = proto; 924 proxy_entry->proxy_port = htons(proxy_port); 925 proxy_entry->server_port = htons(server_port); 926 proxy_entry->server_addr = server_addr; 927 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 928 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 929 proxy_entry->src_mask = src_mask; 930 proxy_entry->dst_mask = dst_mask; 931 932 RuleAdd(la, proxy_entry); 933 934 return (0); 935 } 936