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 a of 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 #include <ctype.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <netdb.h> 62 63 #include <sys/types.h> 64 #include <sys/socket.h> 65 66 /* BSD IPV4 includes */ 67 #include <netinet/in_systm.h> 68 #include <netinet/in.h> 69 #include <netinet/ip.h> 70 #include <netinet/tcp.h> 71 72 #include <arpa/inet.h> 73 74 #include "alias_local.h" /* Functions used by alias*.c */ 75 #include "alias.h" /* Public API functions for libalias */ 76 77 78 79 /* 80 Data structures 81 */ 82 83 /* 84 * A linked list of arbitrary length, based on struct proxy_entry is 85 * used to store proxy rules. 86 */ 87 struct proxy_entry 88 { 89 #define PROXY_TYPE_ENCODE_NONE 1 90 #define PROXY_TYPE_ENCODE_TCPSTREAM 2 91 #define PROXY_TYPE_ENCODE_IPHDR 3 92 int rule_index; 93 int proxy_type; 94 u_char proto; 95 u_short proxy_port; 96 u_short server_port; 97 98 struct in_addr server_addr; 99 100 struct in_addr src_addr; 101 struct in_addr src_mask; 102 103 struct in_addr dst_addr; 104 struct in_addr dst_mask; 105 106 struct proxy_entry *next; 107 struct proxy_entry *last; 108 }; 109 110 111 112 /* 113 File scope variables 114 */ 115 116 static struct proxy_entry *proxyList; 117 118 119 120 /* Local (static) functions: 121 122 IpMask() -- Utility function for creating IP 123 masks from integer (1-32) specification. 124 IpAddr() -- Utility function for converting string 125 to IP address 126 IpPort() -- Utility function for converting string 127 to port number 128 RuleAdd() -- Adds an element to the rule list. 129 RuleDelete() -- Removes an element from the rule list. 130 RuleNumberDelete() -- Removes all elements from the rule list 131 having a certain rule number. 132 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 133 of a TCP stream. 134 ProxyEncodeIpHeader() -- Adds an IP option indicating the true 135 destination of a proxied IP packet 136 */ 137 138 static int IpMask(int, struct in_addr *); 139 static int IpAddr(char *, struct in_addr *); 140 static int IpPort(char *, int, int *); 141 static void RuleAdd(struct proxy_entry *); 142 static void RuleDelete(struct proxy_entry *); 143 static int RuleNumberDelete(int); 144 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 145 static void ProxyEncodeIpHeader(struct ip *, int); 146 147 static int 148 IpMask(int nbits, struct in_addr *mask) 149 { 150 int i; 151 u_int imask; 152 153 if (nbits < 0 || nbits > 32) 154 return -1; 155 156 imask = 0; 157 for (i=0; i<nbits; i++) 158 imask = (imask >> 1) + 0x80000000; 159 mask->s_addr = htonl(imask); 160 161 return 0; 162 } 163 164 static int 165 IpAddr(char *s, struct in_addr *addr) 166 { 167 if (inet_aton(s, addr) == 0) 168 return -1; 169 else 170 return 0; 171 } 172 173 static int 174 IpPort(char *s, int proto, int *port) 175 { 176 int n; 177 178 n = sscanf(s, "%d", port); 179 if (n != 1) 180 { 181 struct servent *se; 182 183 if (proto == IPPROTO_TCP) 184 se = getservbyname(s, "tcp"); 185 else if (proto == IPPROTO_UDP) 186 se = getservbyname(s, "udp"); 187 else 188 return -1; 189 190 if (se == NULL) 191 return -1; 192 193 *port = (u_int) ntohs(se->s_port); 194 } 195 196 return 0; 197 } 198 199 void 200 RuleAdd(struct proxy_entry *entry) 201 { 202 int rule_index; 203 struct proxy_entry *ptr; 204 struct proxy_entry *ptr_last; 205 206 if (proxyList == NULL) 207 { 208 proxyList = entry; 209 entry->last = NULL; 210 entry->next = NULL; 211 return; 212 } 213 214 rule_index = entry->rule_index; 215 ptr = proxyList; 216 ptr_last = NULL; 217 while (ptr != NULL) 218 { 219 if (ptr->rule_index >= rule_index) 220 { 221 if (ptr_last == NULL) 222 { 223 entry->next = proxyList; 224 entry->last = NULL; 225 proxyList->last = entry; 226 proxyList = entry; 227 return; 228 } 229 230 ptr_last->next = entry; 231 ptr->last = entry; 232 entry->last = ptr->last; 233 entry->next = ptr; 234 return; 235 } 236 ptr_last = ptr; 237 ptr = ptr->next; 238 } 239 240 ptr_last->next = entry; 241 entry->last = ptr_last; 242 entry->next = NULL; 243 } 244 245 static void 246 RuleDelete(struct proxy_entry *entry) 247 { 248 if (entry->last != NULL) 249 entry->last->next = entry->next; 250 else 251 proxyList = entry->next; 252 253 if (entry->next != NULL) 254 entry->next->last = entry->last; 255 256 free(entry); 257 } 258 259 static int 260 RuleNumberDelete(int rule_index) 261 { 262 int err; 263 struct proxy_entry *ptr; 264 265 err = -1; 266 ptr = proxyList; 267 while (ptr != NULL) 268 { 269 struct proxy_entry *ptr_next; 270 271 ptr_next = ptr->next; 272 if (ptr->rule_index == rule_index) 273 { 274 err = 0; 275 RuleDelete(ptr); 276 } 277 278 ptr = ptr_next; 279 } 280 281 return err; 282 } 283 284 static void 285 ProxyEncodeTcpStream(struct alias_link *link, 286 struct ip *pip, 287 int maxpacketsize) 288 { 289 int slen; 290 char buffer[40]; 291 struct tcphdr *tc; 292 293 /* Compute pointer to tcp header */ 294 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 295 296 /* Don't modify if once already modified */ 297 298 if (GetAckModified (link)) 299 return; 300 301 /* Translate destination address and port to string form */ 302 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 303 inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link))); 304 305 /* Pad string out to a multiple of two in length */ 306 slen = strlen(buffer); 307 switch (slen % 2) 308 { 309 case 0: 310 strcat(buffer, " \n"); 311 slen += 2; 312 break; 313 case 1: 314 strcat(buffer, "\n"); 315 slen += 1; 316 } 317 318 /* Check for packet overflow */ 319 if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 320 return; 321 322 /* Shift existing TCP data and insert destination string */ 323 { 324 int dlen; 325 int hlen; 326 u_char *p; 327 328 hlen = (pip->ip_hl + tc->th_off) << 2; 329 dlen = ntohs (pip->ip_len) - hlen; 330 331 /* Modify first packet that has data in it */ 332 333 if (dlen == 0) 334 return; 335 336 p = (char *) pip; 337 p += hlen; 338 339 memmove(p + slen, p, dlen); 340 memcpy(p, buffer, slen); 341 } 342 343 /* Save information about modfied sequence number */ 344 { 345 int delta; 346 347 SetAckModified(link); 348 delta = GetDeltaSeqOut(pip, link); 349 AddSeq(pip, link, delta+slen); 350 } 351 352 /* Update IP header packet length and checksum */ 353 { 354 int accumulate; 355 356 accumulate = pip->ip_len; 357 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 358 accumulate -= pip->ip_len; 359 360 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 361 } 362 363 /* Update TCP checksum, Use TcpChecksum since so many things have 364 already changed. */ 365 366 tc->th_sum = 0; 367 tc->th_sum = TcpChecksum (pip); 368 } 369 370 static void 371 ProxyEncodeIpHeader(struct ip *pip, 372 int maxpacketsize) 373 { 374 #define OPTION_LEN_BYTES 8 375 #define OPTION_LEN_INT16 4 376 #define OPTION_LEN_INT32 2 377 u_char option[OPTION_LEN_BYTES]; 378 379 #ifdef DEBUG 380 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 381 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 382 #endif 383 384 /* Check to see that there is room to add an IP option */ 385 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 386 return; 387 388 /* Build option and copy into packet */ 389 { 390 u_char *ptr; 391 struct tcphdr *tc; 392 393 ptr = (u_char *) pip; 394 ptr += 20; 395 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 396 397 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 398 option[1] = OPTION_LEN_BYTES; 399 400 memcpy(&option[2], (u_char *) &pip->ip_dst, 4); 401 402 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 403 memcpy(&option[6], (u_char *) &tc->th_sport, 2); 404 405 memcpy(ptr, option, 8); 406 } 407 408 /* Update checksum, header length and packet length */ 409 { 410 int i; 411 int accumulate; 412 u_short *sptr; 413 414 sptr = (u_short *) option; 415 accumulate = 0; 416 for (i=0; i<OPTION_LEN_INT16; i++) 417 accumulate -= *(sptr++); 418 419 sptr = (u_short *) pip; 420 accumulate += *sptr; 421 pip->ip_hl += OPTION_LEN_INT32; 422 accumulate -= *sptr; 423 424 accumulate += pip->ip_len; 425 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 426 accumulate -= pip->ip_len; 427 428 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 429 } 430 #undef OPTION_LEN_BYTES 431 #undef OPTION_LEN_INT16 432 #undef OPTION_LEN_INT32 433 #ifdef DEBUG 434 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 435 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 436 #endif 437 } 438 439 440 /* Functions by other packet alias source files 441 442 ProxyCheck() -- Checks whether an outgoing packet should 443 be proxied. 444 ProxyModify() -- Encodes the original destination address/port 445 for a packet which is to be redirected to 446 a proxy server. 447 */ 448 449 int 450 ProxyCheck(struct ip *pip, 451 struct in_addr *proxy_server_addr, 452 u_short *proxy_server_port) 453 { 454 u_short dst_port; 455 struct in_addr src_addr; 456 struct in_addr dst_addr; 457 struct proxy_entry *ptr; 458 459 src_addr = pip->ip_src; 460 dst_addr = pip->ip_dst; 461 dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2))) 462 ->th_dport; 463 464 ptr = proxyList; 465 while (ptr != NULL) 466 { 467 u_short proxy_port; 468 469 proxy_port = ptr->proxy_port; 470 if ((dst_port == proxy_port || proxy_port == 0) 471 && pip->ip_p == ptr->proto 472 && src_addr.s_addr != ptr->server_addr.s_addr) 473 { 474 struct in_addr src_addr_masked; 475 struct in_addr dst_addr_masked; 476 477 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 478 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 479 480 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 481 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) 482 { 483 if ((*proxy_server_port = ptr->server_port) == 0) 484 *proxy_server_port = dst_port; 485 *proxy_server_addr = ptr->server_addr; 486 return ptr->proxy_type; 487 } 488 } 489 ptr = ptr->next; 490 } 491 492 return 0; 493 } 494 495 void 496 ProxyModify(struct alias_link *link, 497 struct ip *pip, 498 int maxpacketsize, 499 int proxy_type) 500 { 501 switch (proxy_type) 502 { 503 case PROXY_TYPE_ENCODE_IPHDR: 504 ProxyEncodeIpHeader(pip, maxpacketsize); 505 break; 506 507 case PROXY_TYPE_ENCODE_TCPSTREAM: 508 ProxyEncodeTcpStream(link, pip, maxpacketsize); 509 break; 510 } 511 } 512 513 514 /* 515 Public API functions 516 */ 517 518 int 519 PacketAliasProxyRule(const char *cmd) 520 { 521 /* 522 * This function takes command strings of the form: 523 * 524 * server <addr>[:<port>] 525 * [port <port>] 526 * [rule n] 527 * [proto tcp|udp] 528 * [src <addr>[/n]] 529 * [dst <addr>[/n]] 530 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 531 * 532 * delete <rule number> 533 * 534 * Subfields can be in arbitrary order. Port numbers and addresses 535 * must be in either numeric or symbolic form. An optional rule number 536 * is used to control the order in which rules are searched. If two 537 * rules have the same number, then search order cannot be guaranteed, 538 * and the rules should be disjoint. If no rule number is specified, 539 * then 0 is used, and group 0 rules are always checked before any 540 * others. 541 */ 542 int i, n, len; 543 int cmd_len; 544 int token_count; 545 int state; 546 char *token; 547 char buffer[256]; 548 char str_port[sizeof(buffer)]; 549 char str_server_port[sizeof(buffer)]; 550 char *res = buffer; 551 552 int rule_index; 553 int proto; 554 int proxy_type; 555 int proxy_port; 556 int server_port; 557 struct in_addr server_addr; 558 struct in_addr src_addr, src_mask; 559 struct in_addr dst_addr, dst_mask; 560 struct proxy_entry *proxy_entry; 561 562 /* Copy command line into a buffer */ 563 cmd += strspn(cmd, " \t"); 564 cmd_len = strlen(cmd); 565 if (cmd_len > (sizeof(buffer) - 1)) 566 return -1; 567 strcpy(buffer, cmd); 568 569 /* Convert to lower case */ 570 len = strlen(buffer); 571 for (i=0; i<len; i++) 572 buffer[i] = tolower((unsigned char)buffer[i]); 573 574 /* Set default proxy type */ 575 576 /* Set up default values */ 577 rule_index = 0; 578 proxy_type = PROXY_TYPE_ENCODE_NONE; 579 proto = IPPROTO_TCP; 580 proxy_port = 0; 581 server_addr.s_addr = 0; 582 server_port = 0; 583 src_addr.s_addr = 0; 584 IpMask(0, &src_mask); 585 dst_addr.s_addr = 0; 586 IpMask(0, &dst_mask); 587 588 str_port[0] = 0; 589 str_server_port[0] = 0; 590 591 /* Parse command string with state machine */ 592 #define STATE_READ_KEYWORD 0 593 #define STATE_READ_TYPE 1 594 #define STATE_READ_PORT 2 595 #define STATE_READ_SERVER 3 596 #define STATE_READ_RULE 4 597 #define STATE_READ_DELETE 5 598 #define STATE_READ_PROTO 6 599 #define STATE_READ_SRC 7 600 #define STATE_READ_DST 8 601 state = STATE_READ_KEYWORD; 602 token = strsep(&res, " \t"); 603 token_count = 0; 604 while (token != NULL) 605 { 606 token_count++; 607 switch (state) 608 { 609 case STATE_READ_KEYWORD: 610 if (strcmp(token, "type") == 0) 611 state = STATE_READ_TYPE; 612 else if (strcmp(token, "port") == 0) 613 state = STATE_READ_PORT; 614 else if (strcmp(token, "server") == 0) 615 state = STATE_READ_SERVER; 616 else if (strcmp(token, "rule") == 0) 617 state = STATE_READ_RULE; 618 else if (strcmp(token, "delete") == 0) 619 state = STATE_READ_DELETE; 620 else if (strcmp(token, "proto") == 0) 621 state = STATE_READ_PROTO; 622 else if (strcmp(token, "src") == 0) 623 state = STATE_READ_SRC; 624 else if (strcmp(token, "dst") == 0) 625 state = STATE_READ_DST; 626 else 627 return -1; 628 break; 629 630 case STATE_READ_TYPE: 631 if (strcmp(token, "encode_ip_hdr") == 0) 632 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 633 else if (strcmp(token, "encode_tcp_stream") == 0) 634 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 635 else if (strcmp(token, "no_encode") == 0) 636 proxy_type = PROXY_TYPE_ENCODE_NONE; 637 else 638 return -1; 639 state = STATE_READ_KEYWORD; 640 break; 641 642 case STATE_READ_PORT: 643 strcpy(str_port, token); 644 state = STATE_READ_KEYWORD; 645 break; 646 647 case STATE_READ_SERVER: 648 { 649 int err; 650 char *p; 651 char s[sizeof(buffer)]; 652 653 p = token; 654 while (*p != ':' && *p != 0) 655 p++; 656 657 if (*p != ':') 658 { 659 err = IpAddr(token, &server_addr); 660 if (err) 661 return -1; 662 } 663 else 664 { 665 *p = ' '; 666 667 n = sscanf(token, "%s %s", s, str_server_port); 668 if (n != 2) 669 return -1; 670 671 err = IpAddr(s, &server_addr); 672 if (err) 673 return -1; 674 } 675 } 676 state = STATE_READ_KEYWORD; 677 break; 678 679 case STATE_READ_RULE: 680 n = sscanf(token, "%d", &rule_index); 681 if (n != 1 || rule_index < 0) 682 return -1; 683 state = STATE_READ_KEYWORD; 684 break; 685 686 case STATE_READ_DELETE: 687 { 688 int err; 689 int rule_to_delete; 690 691 if (token_count != 2) 692 return -1; 693 694 n = sscanf(token, "%d", &rule_to_delete); 695 if (n != 1) 696 return -1; 697 err = RuleNumberDelete(rule_to_delete); 698 if (err) 699 return -1; 700 return 0; 701 } 702 703 case STATE_READ_PROTO: 704 if (strcmp(token, "tcp") == 0) 705 proto = IPPROTO_TCP; 706 else if (strcmp(token, "udp") == 0) 707 proto = IPPROTO_UDP; 708 else 709 return -1; 710 state = STATE_READ_KEYWORD; 711 break; 712 713 case STATE_READ_SRC: 714 case STATE_READ_DST: 715 { 716 int err; 717 char *p; 718 struct in_addr mask; 719 struct in_addr addr; 720 721 p = token; 722 while (*p != '/' && *p != 0) 723 p++; 724 725 if (*p != '/') 726 { 727 IpMask(32, &mask); 728 err = IpAddr(token, &addr); 729 if (err) 730 return -1; 731 } 732 else 733 { 734 int nbits; 735 char s[sizeof(buffer)]; 736 737 *p = ' '; 738 n = sscanf(token, "%s %d", s, &nbits); 739 if (n != 2) 740 return -1; 741 742 err = IpAddr(s, &addr); 743 if (err) 744 return -1; 745 746 err = IpMask(nbits, &mask); 747 if (err) 748 return -1; 749 } 750 751 if (state == STATE_READ_SRC) 752 { 753 src_addr = addr; 754 src_mask = mask; 755 } 756 else 757 { 758 dst_addr = addr; 759 dst_mask = mask; 760 } 761 } 762 state = STATE_READ_KEYWORD; 763 break; 764 765 default: 766 return -1; 767 break; 768 } 769 770 do { 771 token = strsep(&res, " \t"); 772 } while (token != NULL && !*token); 773 } 774 #undef STATE_READ_KEYWORD 775 #undef STATE_READ_TYPE 776 #undef STATE_READ_PORT 777 #undef STATE_READ_SERVER 778 #undef STATE_READ_RULE 779 #undef STATE_READ_DELETE 780 #undef STATE_READ_PROTO 781 #undef STATE_READ_SRC 782 #undef STATE_READ_DST 783 784 /* Convert port strings to numbers. This needs to be done after 785 the string is parsed, because the prototype might not be designated 786 before the ports (which might be symbolic entries in /etc/services) */ 787 788 if (strlen(str_port) != 0) 789 { 790 int err; 791 792 err = IpPort(str_port, proto, &proxy_port); 793 if (err) 794 return -1; 795 } 796 else 797 { 798 proxy_port = 0; 799 } 800 801 if (strlen(str_server_port) != 0) 802 { 803 int err; 804 805 err = IpPort(str_server_port, proto, &server_port); 806 if (err) 807 return -1; 808 } 809 else 810 { 811 server_port = 0; 812 } 813 814 /* Check that at least the server address has been defined */ 815 if (server_addr.s_addr == 0) 816 return -1; 817 818 /* Add to linked list */ 819 proxy_entry = malloc(sizeof(struct proxy_entry)); 820 if (proxy_entry == NULL) 821 return -1; 822 823 proxy_entry->proxy_type = proxy_type; 824 proxy_entry->rule_index = rule_index; 825 proxy_entry->proto = proto; 826 proxy_entry->proxy_port = htons(proxy_port); 827 proxy_entry->server_port = htons(server_port); 828 proxy_entry->server_addr = server_addr; 829 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 830 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 831 proxy_entry->src_mask = src_mask; 832 proxy_entry->dst_mask = dst_mask; 833 834 RuleAdd(proxy_entry); 835 836 return 0; 837 } 838