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