alias_proxy.c revision 145932
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: head/sys/netinet/libalias/alias_proxy.c 145932 2005-05-05 21:55:17Z glebius $"); 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 */ 97struct 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 146static int IpMask(int, struct in_addr *); 147static int IpAddr(char *, struct in_addr *); 148static int IpPort(char *, int, int *); 149static void RuleAdd(struct libalias *la, struct proxy_entry *); 150static void RuleDelete(struct proxy_entry *); 151static int RuleNumberDelete(struct libalias *la, int); 152static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 153static void ProxyEncodeIpHeader(struct ip *, int); 154 155static int 156IpMask(int nbits, struct in_addr *mask) 157{ 158 int i; 159 u_int imask; 160 161 if (nbits < 0 || nbits > 32) 162 return (-1); 163 164 imask = 0; 165 for (i = 0; i < nbits; i++) 166 imask = (imask >> 1) + 0x80000000; 167 mask->s_addr = htonl(imask); 168 169 return (0); 170} 171 172static int 173IpAddr(char *s, struct in_addr *addr) 174{ 175 if (inet_aton(s, addr) == 0) 176 return (-1); 177 else 178 return (0); 179} 180 181static int 182IpPort(char *s, int proto, int *port) 183{ 184 int n; 185 186 n = sscanf(s, "%d", port); 187 if (n != 1) { 188 struct servent *se; 189 190 if (proto == IPPROTO_TCP) 191 se = getservbyname(s, "tcp"); 192 else if (proto == IPPROTO_UDP) 193 se = getservbyname(s, "udp"); 194 else 195 return (-1); 196 197 if (se == NULL) 198 return (-1); 199 200 *port = (u_int) ntohs(se->s_port); 201 } 202 return (0); 203} 204 205void 206RuleAdd(struct libalias *la, struct proxy_entry *entry) 207{ 208 int rule_index; 209 struct proxy_entry *ptr; 210 struct proxy_entry *ptr_last; 211 212 if (la->proxyList == NULL) { 213 la->proxyList = entry; 214 entry->last = NULL; 215 entry->next = NULL; 216 return; 217 } 218 entry->la = la; 219 220 rule_index = entry->rule_index; 221 ptr = la->proxyList; 222 ptr_last = NULL; 223 while (ptr != NULL) { 224 if (ptr->rule_index >= rule_index) { 225 if (ptr_last == NULL) { 226 entry->next = la->proxyList; 227 entry->last = NULL; 228 la->proxyList->last = entry; 229 la->proxyList = entry; 230 return; 231 } 232 ptr_last->next = entry; 233 ptr->last = entry; 234 entry->last = ptr->last; 235 entry->next = ptr; 236 return; 237 } 238 ptr_last = ptr; 239 ptr = ptr->next; 240 } 241 242 ptr_last->next = entry; 243 entry->last = ptr_last; 244 entry->next = NULL; 245} 246 247static void 248RuleDelete(struct proxy_entry *entry) 249{ 250 struct libalias *la; 251 252 la = entry->la; 253 if (entry->last != NULL) 254 entry->last->next = entry->next; 255 else 256 la->proxyList = entry->next; 257 258 if (entry->next != NULL) 259 entry->next->last = entry->last; 260 261 free(entry); 262} 263 264static int 265RuleNumberDelete(struct libalias *la, int rule_index) 266{ 267 int err; 268 struct proxy_entry *ptr; 269 270 err = -1; 271 ptr = la->proxyList; 272 while (ptr != NULL) { 273 struct proxy_entry *ptr_next; 274 275 ptr_next = ptr->next; 276 if (ptr->rule_index == rule_index) { 277 err = 0; 278 RuleDelete(ptr); 279 } 280 ptr = ptr_next; 281 } 282 283 return (err); 284} 285 286static void 287ProxyEncodeTcpStream(struct alias_link *lnk, 288 struct ip *pip, 289 int maxpacketsize) 290{ 291 int slen; 292 char buffer[40]; 293 struct tcphdr *tc; 294 295/* Compute pointer to tcp header */ 296 tc = (struct tcphdr *)ip_next(pip); 297 298/* Don't modify if once already modified */ 299 300 if (GetAckModified(lnk)) 301 return; 302 303/* Translate destination address and port to string form */ 304 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 305 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 306 307/* Pad string out to a multiple of two in length */ 308 slen = strlen(buffer); 309 switch (slen % 2) { 310 case 0: 311 strcat(buffer, " \n"); 312 slen += 2; 313 break; 314 case 1: 315 strcat(buffer, "\n"); 316 slen += 1; 317 } 318 319/* Check for packet overflow */ 320 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 321 return; 322 323/* Shift existing TCP data and insert destination string */ 324 { 325 int dlen; 326 int hlen; 327 u_char *p; 328 329 hlen = (pip->ip_hl + tc->th_off) << 2; 330 dlen = ntohs(pip->ip_len) - hlen; 331 332/* Modify first packet that has data in it */ 333 334 if (dlen == 0) 335 return; 336 337 p = (char *)pip; 338 p += hlen; 339 340 bcopy(p, p + slen, dlen); 341 memcpy(p, buffer, slen); 342 } 343 344/* Save information about modfied sequence number */ 345 { 346 int delta; 347 348 SetAckModified(lnk); 349 delta = GetDeltaSeqOut(pip, lnk); 350 AddSeq(pip, lnk, delta + slen); 351 } 352 353/* Update IP header packet length and checksum */ 354 { 355 int accumulate; 356 357 accumulate = pip->ip_len; 358 pip->ip_len = htons(ntohs(pip->ip_len) + slen); 359 accumulate -= pip->ip_len; 360 361 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 362 } 363 364/* Update TCP checksum, Use TcpChecksum since so many things have 365 already changed. */ 366 367 tc->th_sum = 0; 368 tc->th_sum = TcpChecksum(pip); 369} 370 371static void 372ProxyEncodeIpHeader(struct ip *pip, 373 int maxpacketsize) 374{ 375#define OPTION_LEN_BYTES 8 376#define OPTION_LEN_INT16 4 377#define OPTION_LEN_INT32 2 378 u_char option[OPTION_LEN_BYTES]; 379 380#ifdef DEBUG 381 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 382 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 383#endif 384 385 (void)maxpacketsize; 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 *)ip_next(pip); 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 452int 453ProxyCheck(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 *)ip_next(pip)) 465 ->th_dport; 466 467 ptr = la->proxyList; 468 while (ptr != NULL) { 469 u_short proxy_port; 470 471 proxy_port = ptr->proxy_port; 472 if ((dst_port == proxy_port || proxy_port == 0) 473 && pip->ip_p == ptr->proto 474 && src_addr.s_addr != ptr->server_addr.s_addr) { 475 struct in_addr src_addr_masked; 476 struct in_addr dst_addr_masked; 477 478 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 479 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 480 481 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 482 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 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 495void 496ProxyModify(struct libalias *la, struct alias_link *lnk, 497 struct ip *pip, 498 int maxpacketsize, 499 int proxy_type) 500{ 501 502 (void)la; 503 504 switch (proxy_type) { 505 case PROXY_TYPE_ENCODE_IPHDR: 506 ProxyEncodeIpHeader(pip, maxpacketsize); 507 break; 508 509 case PROXY_TYPE_ENCODE_TCPSTREAM: 510 ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 511 break; 512 } 513} 514 515 516/* 517 Public API functions 518*/ 519 520int 521LibAliasProxyRule(struct libalias *la, const char *cmd) 522{ 523/* 524 * This function takes command strings of the form: 525 * 526 * server <addr>[:<port>] 527 * [port <port>] 528 * [rule n] 529 * [proto tcp|udp] 530 * [src <addr>[/n]] 531 * [dst <addr>[/n]] 532 * [type encode_tcp_stream|encode_ip_hdr|no_encode] 533 * 534 * delete <rule number> 535 * 536 * Subfields can be in arbitrary order. Port numbers and addresses 537 * must be in either numeric or symbolic form. An optional rule number 538 * is used to control the order in which rules are searched. If two 539 * rules have the same number, then search order cannot be guaranteed, 540 * and the rules should be disjoint. If no rule number is specified, 541 * then 0 is used, and group 0 rules are always checked before any 542 * others. 543 */ 544 int i, n, len; 545 int cmd_len; 546 int token_count; 547 int state; 548 char *token; 549 char buffer[256]; 550 char str_port[sizeof(buffer)]; 551 char str_server_port[sizeof(buffer)]; 552 char *res = buffer; 553 554 int rule_index; 555 int proto; 556 int proxy_type; 557 int proxy_port; 558 int server_port; 559 struct in_addr server_addr; 560 struct in_addr src_addr, src_mask; 561 struct in_addr dst_addr, dst_mask; 562 struct proxy_entry *proxy_entry; 563 564/* Copy command line into a buffer */ 565 cmd += strspn(cmd, " \t"); 566 cmd_len = strlen(cmd); 567 if (cmd_len > (int)(sizeof(buffer) - 1)) 568 return (-1); 569 strcpy(buffer, cmd); 570 571/* Convert to lower case */ 572 len = strlen(buffer); 573 for (i = 0; i < len; i++) 574 buffer[i] = tolower((unsigned char)buffer[i]); 575 576/* Set default proxy type */ 577 578/* Set up default values */ 579 rule_index = 0; 580 proxy_type = PROXY_TYPE_ENCODE_NONE; 581 proto = IPPROTO_TCP; 582 proxy_port = 0; 583 server_addr.s_addr = 0; 584 server_port = 0; 585 src_addr.s_addr = 0; 586 IpMask(0, &src_mask); 587 dst_addr.s_addr = 0; 588 IpMask(0, &dst_mask); 589 590 str_port[0] = 0; 591 str_server_port[0] = 0; 592 593/* Parse command string with state machine */ 594#define STATE_READ_KEYWORD 0 595#define STATE_READ_TYPE 1 596#define STATE_READ_PORT 2 597#define STATE_READ_SERVER 3 598#define STATE_READ_RULE 4 599#define STATE_READ_DELETE 5 600#define STATE_READ_PROTO 6 601#define STATE_READ_SRC 7 602#define STATE_READ_DST 8 603 state = STATE_READ_KEYWORD; 604 token = strsep(&res, " \t"); 605 token_count = 0; 606 while (token != NULL) { 607 token_count++; 608 switch (state) { 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 err = IpAddr(token, &server_addr); 659 if (err) 660 return (-1); 661 } else { 662 *p = ' '; 663 664 n = sscanf(token, "%s %s", s, str_server_port); 665 if (n != 2) 666 return (-1); 667 668 err = IpAddr(s, &server_addr); 669 if (err) 670 return (-1); 671 } 672 } 673 state = STATE_READ_KEYWORD; 674 break; 675 676 case STATE_READ_RULE: 677 n = sscanf(token, "%d", &rule_index); 678 if (n != 1 || rule_index < 0) 679 return (-1); 680 state = STATE_READ_KEYWORD; 681 break; 682 683 case STATE_READ_DELETE: 684 { 685 int err; 686 int rule_to_delete; 687 688 if (token_count != 2) 689 return (-1); 690 691 n = sscanf(token, "%d", &rule_to_delete); 692 if (n != 1) 693 return (-1); 694 err = RuleNumberDelete(la, rule_to_delete); 695 if (err) 696 return (-1); 697 return (0); 698 } 699 700 case STATE_READ_PROTO: 701 if (strcmp(token, "tcp") == 0) 702 proto = IPPROTO_TCP; 703 else if (strcmp(token, "udp") == 0) 704 proto = IPPROTO_UDP; 705 else 706 return (-1); 707 state = STATE_READ_KEYWORD; 708 break; 709 710 case STATE_READ_SRC: 711 case STATE_READ_DST: 712 { 713 int err; 714 char *p; 715 struct in_addr mask; 716 struct in_addr addr; 717 718 p = token; 719 while (*p != '/' && *p != 0) 720 p++; 721 722 if (*p != '/') { 723 IpMask(32, &mask); 724 err = IpAddr(token, &addr); 725 if (err) 726 return (-1); 727 } else { 728 int nbits; 729 char s[sizeof(buffer)]; 730 731 *p = ' '; 732 n = sscanf(token, "%s %d", s, &nbits); 733 if (n != 2) 734 return (-1); 735 736 err = IpAddr(s, &addr); 737 if (err) 738 return (-1); 739 740 err = IpMask(nbits, &mask); 741 if (err) 742 return (-1); 743 } 744 745 if (state == STATE_READ_SRC) { 746 src_addr = addr; 747 src_mask = mask; 748 } else { 749 dst_addr = addr; 750 dst_mask = mask; 751 } 752 } 753 state = STATE_READ_KEYWORD; 754 break; 755 756 default: 757 return (-1); 758 break; 759 } 760 761 do { 762 token = strsep(&res, " \t"); 763 } while (token != NULL && !*token); 764 } 765#undef STATE_READ_KEYWORD 766#undef STATE_READ_TYPE 767#undef STATE_READ_PORT 768#undef STATE_READ_SERVER 769#undef STATE_READ_RULE 770#undef STATE_READ_DELETE 771#undef STATE_READ_PROTO 772#undef STATE_READ_SRC 773#undef STATE_READ_DST 774 775/* Convert port strings to numbers. This needs to be done after 776 the string is parsed, because the prototype might not be designated 777 before the ports (which might be symbolic entries in /etc/services) */ 778 779 if (strlen(str_port) != 0) { 780 int err; 781 782 err = IpPort(str_port, proto, &proxy_port); 783 if (err) 784 return (-1); 785 } else { 786 proxy_port = 0; 787 } 788 789 if (strlen(str_server_port) != 0) { 790 int err; 791 792 err = IpPort(str_server_port, proto, &server_port); 793 if (err) 794 return (-1); 795 } else { 796 server_port = 0; 797 } 798 799/* Check that at least the server address has been defined */ 800 if (server_addr.s_addr == 0) 801 return (-1); 802 803/* Add to linked list */ 804 proxy_entry = malloc(sizeof(struct proxy_entry)); 805 if (proxy_entry == NULL) 806 return (-1); 807 808 proxy_entry->proxy_type = proxy_type; 809 proxy_entry->rule_index = rule_index; 810 proxy_entry->proto = proto; 811 proxy_entry->proxy_port = htons(proxy_port); 812 proxy_entry->server_port = htons(server_port); 813 proxy_entry->server_addr = server_addr; 814 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 815 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 816 proxy_entry->src_mask = src_mask; 817 proxy_entry->dst_mask = dst_mask; 818 819 RuleAdd(la, proxy_entry); 820 821 return (0); 822} 823