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