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 *lnk, 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 *)ip_next(pip); 287 288 /* Don't modify if once already modified */ 289 290 if (GetAckModified(lnk)) 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(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 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 ((int)(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(lnk); 339 delta = GetDeltaSeqOut(pip, lnk); 340 AddSeq(pip, lnk, 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 (void)maxpacketsize; 376 377 /* Check to see that there is room to add an IP option */ 378 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 379 return; 380 381 /* Build option and copy into packet */ 382 { 383 u_char *ptr; 384 struct tcphdr *tc; 385 386 ptr = (u_char *) pip; 387 ptr += 20; 388 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 389 390 option[0] = 0x64; /* class: 3 (reserved), option 4 */ 391 option[1] = OPTION_LEN_BYTES; 392 393 memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 394 395 tc = (struct tcphdr *)ip_next(pip); 396 memcpy(&option[6], (u_char *) & tc->th_sport, 2); 397 398 memcpy(ptr, option, 8); 399 } 400 401 /* Update checksum, header length and packet length */ 402 { 403 int i; 404 int accumulate; 405 u_short *sptr; 406 407 sptr = (u_short *) option; 408 accumulate = 0; 409 for (i = 0; i < OPTION_LEN_INT16; i++) 410 accumulate -= *(sptr++); 411 412 sptr = (u_short *) pip; 413 accumulate += *sptr; 414 pip->ip_hl += OPTION_LEN_INT32; 415 accumulate -= *sptr; 416 417 accumulate += pip->ip_len; 418 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 419 accumulate -= pip->ip_len; 420 421 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 422 } 423 #undef OPTION_LEN_BYTES 424 #undef OPTION_LEN_INT16 425 #undef OPTION_LEN_INT32 426 #ifdef DEBUG 427 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 428 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 429 #endif 430 } 431 432 433 /* Functions by other packet alias source files 434 435 ProxyCheck() -- Checks whether an outgoing packet should 436 be proxied. 437 ProxyModify() -- Encodes the original destination address/port 438 for a packet which is to be redirected to 439 a proxy server. 440 */ 441 442 int 443 ProxyCheck(struct libalias *la, struct ip *pip, 444 struct in_addr *proxy_server_addr, 445 u_short * proxy_server_port) 446 { 447 u_short dst_port; 448 struct in_addr src_addr; 449 struct in_addr dst_addr; 450 struct proxy_entry *ptr; 451 452 src_addr = pip->ip_src; 453 dst_addr = pip->ip_dst; 454 dst_port = ((struct tcphdr *)ip_next(pip)) 455 ->th_dport; 456 457 ptr = la->proxyList; 458 while (ptr != NULL) { 459 u_short proxy_port; 460 461 proxy_port = ptr->proxy_port; 462 if ((dst_port == proxy_port || proxy_port == 0) 463 && pip->ip_p == ptr->proto 464 && src_addr.s_addr != ptr->server_addr.s_addr) { 465 struct in_addr src_addr_masked; 466 struct in_addr dst_addr_masked; 467 468 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 469 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 470 471 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 472 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 473 if ((*proxy_server_port = ptr->server_port) == 0) 474 *proxy_server_port = dst_port; 475 *proxy_server_addr = ptr->server_addr; 476 return (ptr->proxy_type); 477 } 478 } 479 ptr = ptr->next; 480 } 481 482 return (0); 483 } 484 485 void 486 ProxyModify(struct libalias *la, struct alias_link *lnk, 487 struct ip *pip, 488 int maxpacketsize, 489 int proxy_type) 490 { 491 492 (void)la; 493 494 switch (proxy_type) { 495 case PROXY_TYPE_ENCODE_IPHDR: 496 ProxyEncodeIpHeader(pip, maxpacketsize); 497 break; 498 499 case PROXY_TYPE_ENCODE_TCPSTREAM: 500 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 501 break; 502 } 503 } 504 505 506 /* 507 Public API functions 508 */ 509 510 int 511 LibAliasProxyRule(struct libalias *la, const char *cmd) 512 { 513 /* 514 * This function takes command strings of the form: 515 * 516 * server <addr>[:<port>] 517 * [port <port>] 518 * [rule n] 519 * [proto tcp|udp] 520 * [src <addr>[/n]] 521 * [dst <addr>[/n]] 522 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 523 * 524 * delete <rule number> 525 * 526 * Subfields can be in arbitrary order. Port numbers and addresses 527 * must be in either numeric or symbolic form. An optional rule number 528 * is used to control the order in which rules are searched. If two 529 * rules have the same number, then search order cannot be guaranteed, 530 * and the rules should be disjoint. If no rule number is specified, 531 * then 0 is used, and group 0 rules are always checked before any 532 * others. 533 */ 534 int i, n, len; 535 int cmd_len; 536 int token_count; 537 int state; 538 char *token; 539 char buffer[256]; 540 char str_port[sizeof(buffer)]; 541 char str_server_port[sizeof(buffer)]; 542 char *res = buffer; 543 544 int rule_index; 545 int proto; 546 int proxy_type; 547 int proxy_port; 548 int server_port; 549 struct in_addr server_addr; 550 struct in_addr src_addr, src_mask; 551 struct in_addr dst_addr, dst_mask; 552 struct proxy_entry *proxy_entry; 553 554 /* Copy command line into a buffer */ 555 cmd += strspn(cmd, " \t"); 556 cmd_len = strlen(cmd); 557 if (cmd_len > (int)(sizeof(buffer) - 1)) 558 return (-1); 559 strcpy(buffer, cmd); 560 561 /* Convert to lower case */ 562 len = strlen(buffer); 563 for (i = 0; i < len; i++) 564 buffer[i] = tolower((unsigned char)buffer[i]); 565 566 /* Set default proxy type */ 567 568 /* Set up default values */ 569 rule_index = 0; 570 proxy_type = PROXY_TYPE_ENCODE_NONE; 571 proto = IPPROTO_TCP; 572 proxy_port = 0; 573 server_addr.s_addr = 0; 574 server_port = 0; 575 src_addr.s_addr = 0; 576 IpMask(0, &src_mask); 577 dst_addr.s_addr = 0; 578 IpMask(0, &dst_mask); 579 580 str_port[0] = 0; 581 str_server_port[0] = 0; 582 583 /* Parse command string with state machine */ 584 #define STATE_READ_KEYWORD 0 585 #define STATE_READ_TYPE 1 586 #define STATE_READ_PORT 2 587 #define STATE_READ_SERVER 3 588 #define STATE_READ_RULE 4 589 #define STATE_READ_DELETE 5 590 #define STATE_READ_PROTO 6 591 #define STATE_READ_SRC 7 592 #define STATE_READ_DST 8 593 state = STATE_READ_KEYWORD; 594 token = strsep(&res, " \t"); 595 token_count = 0; 596 while (token != NULL) { 597 token_count++; 598 switch (state) { 599 case STATE_READ_KEYWORD: 600 if (strcmp(token, "type") == 0) 601 state = STATE_READ_TYPE; 602 else if (strcmp(token, "port") == 0) 603 state = STATE_READ_PORT; 604 else if (strcmp(token, "server") == 0) 605 state = STATE_READ_SERVER; 606 else if (strcmp(token, "rule") == 0) 607 state = STATE_READ_RULE; 608 else if (strcmp(token, "delete") == 0) 609 state = STATE_READ_DELETE; 610 else if (strcmp(token, "proto") == 0) 611 state = STATE_READ_PROTO; 612 else if (strcmp(token, "src") == 0) 613 state = STATE_READ_SRC; 614 else if (strcmp(token, "dst") == 0) 615 state = STATE_READ_DST; 616 else 617 return (-1); 618 break; 619 620 case STATE_READ_TYPE: 621 if (strcmp(token, "encode_ip_hdr") == 0) 622 proxy_type = PROXY_TYPE_ENCODE_IPHDR; 623 else if (strcmp(token, "encode_tcp_stream") == 0) 624 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 625 else if (strcmp(token, "no_encode") == 0) 626 proxy_type = PROXY_TYPE_ENCODE_NONE; 627 else 628 return (-1); 629 state = STATE_READ_KEYWORD; 630 break; 631 632 case STATE_READ_PORT: 633 strcpy(str_port, token); 634 state = STATE_READ_KEYWORD; 635 break; 636 637 case STATE_READ_SERVER: 638 { 639 int err; 640 char *p; 641 char s[sizeof(buffer)]; 642 643 p = token; 644 while (*p != ':' && *p != 0) 645 p++; 646 647 if (*p != ':') { 648 err = IpAddr(token, &server_addr); 649 if (err) 650 return (-1); 651 } else { 652 *p = ' '; 653 654 n = sscanf(token, "%s %s", s, str_server_port); 655 if (n != 2) 656 return (-1); 657 658 err = IpAddr(s, &server_addr); 659 if (err) 660 return (-1); 661 } 662 } 663 state = STATE_READ_KEYWORD; 664 break; 665 666 case STATE_READ_RULE: 667 n = sscanf(token, "%d", &rule_index); 668 if (n != 1 || rule_index < 0) 669 return (-1); 670 state = STATE_READ_KEYWORD; 671 break; 672 673 case STATE_READ_DELETE: 674 { 675 int err; 676 int rule_to_delete; 677 678 if (token_count != 2) 679 return (-1); 680 681 n = sscanf(token, "%d", &rule_to_delete); 682 if (n != 1) 683 return (-1); 684 err = RuleNumberDelete(la, rule_to_delete); 685 if (err) 686 return (-1); 687 return (0); 688 } 689 690 case STATE_READ_PROTO: 691 if (strcmp(token, "tcp") == 0) 692 proto = IPPROTO_TCP; 693 else if (strcmp(token, "udp") == 0) 694 proto = IPPROTO_UDP; 695 else 696 return (-1); 697 state = STATE_READ_KEYWORD; 698 break; 699 700 case STATE_READ_SRC: 701 case STATE_READ_DST: 702 { 703 int err; 704 char *p; 705 struct in_addr mask; 706 struct in_addr addr; 707 708 p = token; 709 while (*p != '/' && *p != 0) 710 p++; 711 712 if (*p != '/') { 713 IpMask(32, &mask); 714 err = IpAddr(token, &addr); 715 if (err) 716 return (-1); 717 } else { 718 int nbits; 719 char s[sizeof(buffer)]; 720 721 *p = ' '; 722 n = sscanf(token, "%s %d", s, &nbits); 723 if (n != 2) 724 return (-1); 725 726 err = IpAddr(s, &addr); 727 if (err) 728 return (-1); 729 730 err = IpMask(nbits, &mask); 731 if (err) 732 return (-1); 733 } 734 735 if (state == STATE_READ_SRC) { 736 src_addr = addr; 737 src_mask = mask; 738 } else { 739 dst_addr = addr; 740 dst_mask = mask; 741 } 742 } 743 state = STATE_READ_KEYWORD; 744 break; 745 746 default: 747 return (-1); 748 break; 749 } 750 751 do { 752 token = strsep(&res, " \t"); 753 } while (token != NULL && !*token); 754 } 755 #undef STATE_READ_KEYWORD 756 #undef STATE_READ_TYPE 757 #undef STATE_READ_PORT 758 #undef STATE_READ_SERVER 759 #undef STATE_READ_RULE 760 #undef STATE_READ_DELETE 761 #undef STATE_READ_PROTO 762 #undef STATE_READ_SRC 763 #undef STATE_READ_DST 764 765 /* Convert port strings to numbers. This needs to be done after 766 the string is parsed, because the prototype might not be designated 767 before the ports (which might be symbolic entries in /etc/services) */ 768 769 if (strlen(str_port) != 0) { 770 int err; 771 772 err = IpPort(str_port, proto, &proxy_port); 773 if (err) 774 return (-1); 775 } else { 776 proxy_port = 0; 777 } 778 779 if (strlen(str_server_port) != 0) { 780 int err; 781 782 err = IpPort(str_server_port, proto, &server_port); 783 if (err) 784 return (-1); 785 } else { 786 server_port = 0; 787 } 788 789 /* Check that at least the server address has been defined */ 790 if (server_addr.s_addr == 0) 791 return (-1); 792 793 /* Add to linked list */ 794 proxy_entry = malloc(sizeof(struct proxy_entry)); 795 if (proxy_entry == NULL) 796 return (-1); 797 798 proxy_entry->proxy_type = proxy_type; 799 proxy_entry->rule_index = rule_index; 800 proxy_entry->proto = proto; 801 proxy_entry->proxy_port = htons(proxy_port); 802 proxy_entry->server_port = htons(server_port); 803 proxy_entry->server_addr = server_addr; 804 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 805 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 806 proxy_entry->src_mask = src_mask; 807 proxy_entry->dst_mask = dst_mask; 808 809 RuleAdd(la, proxy_entry); 810 811 return (0); 812 } 813