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