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