Initial import from FreeBSD RELENG_4:
[dragonfly.git] / lib / libalias / alias_proxy.c
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  * $FreeBSD: src/lib/libalias/alias_proxy.c,v 1.4.2.5 2001/11/03 11:34:33 brian Exp $
27  */
28
29 /* file: alias_proxy.c
30
31     This file encapsulates special operations related to transparent
32     proxy redirection.  This is where packets with a particular destination,
33     usually tcp port 80, are redirected to a proxy server.
34
35     When packets are proxied, the destination address and port are
36     modified.  In certain cases, it is necessary to somehow encode
37     the original address/port info into the packet.  Two methods are
38     presently supported: addition of a [DEST addr port] string at the
39     beginning a of tcp stream, or inclusion of an optional field
40     in the IP header.
41     
42     There is one public API function:
43
44         PacketAliasProxyRule()    -- Adds and deletes proxy
45                                      rules.
46
47     Rules are stored in a linear linked list, so lookup efficiency
48     won't be too good for large lists.
49
50
51     Initial development: April, 1998 (cjm)
52 */
53
54
55 /* System includes */
56 #include <ctype.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <netdb.h>
61
62 #include <sys/types.h>
63 #include <sys/socket.h>
64
65 /* BSD IPV4 includes */
66 #include <netinet/in_systm.h>
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <netinet/tcp.h>
70
71 #include <arpa/inet.h>
72
73 #include "alias_local.h"  /* Functions used by alias*.c */
74 #include "alias.h"        /* Public API functions for libalias */
75
76
77
78 /*
79     Data structures
80  */
81
82 /*
83  * A linked list of arbitrary length, based on struct proxy_entry is
84  * used to store proxy rules.
85  */
86 struct proxy_entry
87 {
88 #define PROXY_TYPE_ENCODE_NONE      1
89 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
90 #define PROXY_TYPE_ENCODE_IPHDR     3
91     int rule_index;
92     int proxy_type;
93     u_char proto;
94     u_short proxy_port;
95     u_short server_port;
96
97     struct in_addr server_addr;
98
99     struct in_addr src_addr;
100     struct in_addr src_mask;
101
102     struct in_addr dst_addr;
103     struct in_addr dst_mask;
104
105     struct proxy_entry *next;
106     struct proxy_entry *last;
107 };
108
109
110
111 /*
112     File scope variables
113 */
114
115 static struct proxy_entry *proxyList;
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 proxy_entry *);
141 static void RuleDelete(struct proxy_entry *);
142 static int RuleNumberDelete(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 proxy_entry *entry)
200 {
201     int rule_index;
202     struct proxy_entry *ptr;
203     struct proxy_entry *ptr_last;
204
205     if (proxyList == NULL)
206     {
207         proxyList = entry;
208         entry->last = NULL;
209         entry->next = NULL;
210         return;
211     }
212
213     rule_index = entry->rule_index;
214     ptr = proxyList;
215     ptr_last = NULL;
216     while (ptr != NULL)
217     {
218         if (ptr->rule_index >= rule_index)
219         {
220             if (ptr_last == NULL)
221             {
222                 entry->next = proxyList;
223                 entry->last = NULL;
224                 proxyList->last = entry;
225                 proxyList = entry;
226                 return;
227             }
228
229             ptr_last->next = entry;
230             ptr->last = entry;
231             entry->last = ptr->last;
232             entry->next = ptr;
233             return;
234         }
235         ptr_last = ptr;
236         ptr = ptr->next;
237     }
238
239     ptr_last->next = entry;
240     entry->last = ptr_last;
241     entry->next = NULL;
242 }
243
244 static void
245 RuleDelete(struct proxy_entry *entry)
246 {
247     if (entry->last != NULL)
248         entry->last->next = entry->next;
249     else
250         proxyList = entry->next;
251
252     if (entry->next != NULL)
253         entry->next->last = entry->last;
254
255     free(entry);
256 }
257
258 static int
259 RuleNumberDelete(int rule_index)
260 {
261     int err;
262     struct proxy_entry *ptr;
263
264     err = -1;
265     ptr = proxyList;
266     while (ptr != NULL)
267     {
268         struct proxy_entry *ptr_next;
269
270         ptr_next = ptr->next;
271         if (ptr->rule_index == rule_index)
272         {
273             err = 0;
274             RuleDelete(ptr);
275         }
276
277         ptr = ptr_next;
278     }
279
280     return err;
281 }
282
283 static void
284 ProxyEncodeTcpStream(struct alias_link *link,
285                      struct ip *pip,
286                      int maxpacketsize)
287 {
288     int slen;
289     char buffer[40];
290     struct tcphdr *tc;
291
292 /* Compute pointer to tcp header */
293     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
294
295 /* Don't modify if once already modified */
296
297     if (GetAckModified (link))
298         return;
299
300 /* Translate destination address and port to string form */
301     snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
302         inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link)));
303     
304 /* Pad string out to a multiple of two in length */
305     slen = strlen(buffer);
306     switch (slen % 2)
307     {
308     case 0:
309         strcat(buffer, " \n");
310         slen += 2;
311         break;
312     case 1:
313         strcat(buffer, "\n");
314         slen += 1;
315     }
316
317 /* Check for packet overflow */
318     if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
319         return;
320
321 /* Shift existing TCP data and insert destination string */
322     {
323         int dlen;
324         int hlen;
325         u_char *p;
326
327         hlen = (pip->ip_hl + tc->th_off) << 2;
328         dlen = ntohs (pip->ip_len) - hlen;
329
330 /* Modify first packet that has data in it */
331
332         if (dlen == 0)
333                 return;
334
335         p = (char *) pip;
336         p += hlen;
337
338         memmove(p + slen, p, dlen);
339         memcpy(p, buffer, slen);
340     }
341
342 /* Save information about modfied sequence number */
343     {
344         int delta;
345
346         SetAckModified(link);
347         delta = GetDeltaSeqOut(pip, link);
348         AddSeq(pip, link, delta+slen);
349     }
350
351 /* Update IP header packet length and checksum */
352     {
353         int accumulate;
354
355         accumulate  = pip->ip_len;
356         pip->ip_len = htons(ntohs(pip->ip_len) + slen);
357         accumulate -= pip->ip_len;
358
359         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
360     }
361
362 /* Update TCP checksum, Use TcpChecksum since so many things have
363    already changed. */
364
365     tc->th_sum = 0;
366     tc->th_sum = TcpChecksum (pip);
367 }
368
369 static void
370 ProxyEncodeIpHeader(struct ip *pip,
371                     int maxpacketsize)
372 {
373 #define OPTION_LEN_BYTES  8
374 #define OPTION_LEN_INT16  4
375 #define OPTION_LEN_INT32  2
376     u_char option[OPTION_LEN_BYTES];
377
378 #ifdef DEBUG
379     fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
380     fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
381 #endif
382
383 /* Check to see that there is room to add an IP option */
384     if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
385         return;
386
387 /* Build option and copy into packet */
388     {
389         u_char *ptr;
390         struct tcphdr *tc;
391
392         ptr = (u_char *) pip;
393         ptr += 20;
394         memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
395
396         option[0] = 0x64; /* class: 3 (reserved), option 4 */
397         option[1] = OPTION_LEN_BYTES;
398
399         memcpy(&option[2], (u_char *) &pip->ip_dst, 4);
400
401         tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
402         memcpy(&option[6], (u_char *) &tc->th_sport, 2);
403
404         memcpy(ptr, option, 8);
405     }
406
407 /* Update checksum, header length and packet length */
408     {
409         int i;
410         int accumulate;
411         u_short *sptr;
412
413         sptr = (u_short *) option;
414         accumulate = 0;
415         for (i=0; i<OPTION_LEN_INT16; i++)
416             accumulate -= *(sptr++);
417
418         sptr = (u_short *) pip;
419         accumulate += *sptr;
420         pip->ip_hl += OPTION_LEN_INT32;
421         accumulate -= *sptr;
422
423         accumulate += pip->ip_len;
424         pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
425         accumulate -= pip->ip_len;
426
427         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
428     }
429 #undef OPTION_LEN_BYTES
430 #undef OPTION_LEN_INT16
431 #undef OPTION_LEN_INT32
432 #ifdef DEBUG
433     fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
434     fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
435 #endif
436 }
437
438
439 /* Functions by other packet alias source files
440
441     ProxyCheck()         -- Checks whether an outgoing packet should
442                             be proxied.
443     ProxyModify()        -- Encodes the original destination address/port
444                             for a packet which is to be redirected to
445                             a proxy server.
446 */
447
448 int
449 ProxyCheck(struct ip *pip,
450            struct in_addr *proxy_server_addr,
451            u_short *proxy_server_port)
452 {
453     u_short dst_port;
454     struct in_addr src_addr;
455     struct in_addr dst_addr;
456     struct proxy_entry *ptr;
457
458     src_addr = pip->ip_src;
459     dst_addr = pip->ip_dst;
460     dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)))
461         ->th_dport;
462
463     ptr = proxyList;
464     while (ptr != NULL)
465     {
466         u_short proxy_port;
467
468         proxy_port = ptr->proxy_port;
469         if ((dst_port == proxy_port || proxy_port == 0)
470          && pip->ip_p == ptr->proto
471          && src_addr.s_addr != ptr->server_addr.s_addr)
472         {
473             struct in_addr src_addr_masked;
474             struct in_addr dst_addr_masked;
475
476             src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
477             dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
478
479             if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
480              && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr))
481             {
482                 if ((*proxy_server_port = ptr->server_port) == 0)
483                     *proxy_server_port = dst_port;
484                 *proxy_server_addr = ptr->server_addr;
485                 return ptr->proxy_type;
486             }
487         }
488         ptr = ptr->next;
489     }
490
491     return 0;
492 }
493
494 void
495 ProxyModify(struct alias_link *link,
496             struct ip *pip,
497             int maxpacketsize,
498             int proxy_type)
499 {
500     switch (proxy_type)
501     {
502     case PROXY_TYPE_ENCODE_IPHDR:
503         ProxyEncodeIpHeader(pip, maxpacketsize);
504         break;
505
506     case PROXY_TYPE_ENCODE_TCPSTREAM:
507         ProxyEncodeTcpStream(link, pip, maxpacketsize);
508         break;
509     }
510 }
511
512
513 /*
514     Public API functions
515 */
516
517 int
518 PacketAliasProxyRule(const char *cmd)
519 {
520 /*
521  * This function takes command strings of the form:
522  *
523  *   server <addr>[:<port>]
524  *   [port <port>]
525  *   [rule n]
526  *   [proto tcp|udp]
527  *   [src <addr>[/n]]
528  *   [dst <addr>[/n]]
529  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
530  *
531  *   delete <rule number>
532  *
533  * Subfields can be in arbitrary order.  Port numbers and addresses
534  * must be in either numeric or symbolic form. An optional rule number
535  * is used to control the order in which rules are searched.  If two
536  * rules have the same number, then search order cannot be guaranteed,
537  * and the rules should be disjoint.  If no rule number is specified,
538  * then 0 is used, and group 0 rules are always checked before any
539  * others.
540  */
541     int i, n, len;
542     int cmd_len;
543     int token_count;
544     int state;
545     char *token;
546     char buffer[256];
547     char str_port[sizeof(buffer)];
548     char str_server_port[sizeof(buffer)];
549     char *res = buffer;
550
551     int rule_index;
552     int proto;
553     int proxy_type;
554     int proxy_port;
555     int server_port;
556     struct in_addr server_addr;
557     struct in_addr src_addr, src_mask;
558     struct in_addr dst_addr, dst_mask;
559     struct proxy_entry *proxy_entry;
560
561 /* Copy command line into a buffer */
562     cmd += strspn(cmd, " \t");
563     cmd_len = strlen(cmd);
564     if (cmd_len > (sizeof(buffer) - 1))
565         return -1;
566     strcpy(buffer, cmd);
567
568 /* Convert to lower case */
569     len = strlen(buffer);
570     for (i=0; i<len; i++)
571         buffer[i] = tolower((unsigned char)buffer[i]);
572
573 /* Set default proxy type */
574
575 /* Set up default values */
576     rule_index = 0;
577     proxy_type = PROXY_TYPE_ENCODE_NONE;
578     proto = IPPROTO_TCP;
579     proxy_port = 0;
580     server_addr.s_addr = 0;
581     server_port = 0;
582     src_addr.s_addr = 0;
583     IpMask(0, &src_mask);
584     dst_addr.s_addr = 0;
585     IpMask(0, &dst_mask);
586
587     str_port[0] = 0;
588     str_server_port[0] = 0;
589
590 /* Parse command string with state machine */
591 #define STATE_READ_KEYWORD    0
592 #define STATE_READ_TYPE       1
593 #define STATE_READ_PORT       2
594 #define STATE_READ_SERVER     3
595 #define STATE_READ_RULE       4
596 #define STATE_READ_DELETE     5
597 #define STATE_READ_PROTO      6
598 #define STATE_READ_SRC        7
599 #define STATE_READ_DST        8
600     state = STATE_READ_KEYWORD;
601     token = strsep(&res, " \t");
602     token_count = 0;
603     while (token != NULL)
604     {
605         token_count++;
606         switch (state)
607         {
608         case STATE_READ_KEYWORD:
609             if (strcmp(token, "type") == 0)
610                 state = STATE_READ_TYPE;
611             else if (strcmp(token, "port") == 0)
612                 state = STATE_READ_PORT;
613             else if (strcmp(token, "server") == 0)
614                 state = STATE_READ_SERVER;
615             else if (strcmp(token, "rule") == 0)
616                 state = STATE_READ_RULE;
617             else if (strcmp(token, "delete") == 0)
618                 state = STATE_READ_DELETE;
619             else if (strcmp(token, "proto") == 0)
620                 state = STATE_READ_PROTO;
621             else if (strcmp(token, "src") == 0)
622                 state = STATE_READ_SRC;
623             else if (strcmp(token, "dst") == 0)
624                 state = STATE_READ_DST;
625             else
626                 return -1;
627             break;
628
629         case STATE_READ_TYPE:
630             if (strcmp(token, "encode_ip_hdr") == 0)
631                 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
632             else if (strcmp(token, "encode_tcp_stream") == 0)
633                 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
634             else if (strcmp(token, "no_encode") == 0)
635                 proxy_type = PROXY_TYPE_ENCODE_NONE;
636             else
637                 return -1;
638             state = STATE_READ_KEYWORD;
639             break;
640
641         case STATE_READ_PORT:
642             strcpy(str_port, token);
643             state = STATE_READ_KEYWORD;
644             break;
645
646         case STATE_READ_SERVER:
647             {
648                 int err;
649                 char *p;
650                 char s[sizeof(buffer)];
651
652                 p = token;
653                 while (*p != ':' && *p != 0)
654                     p++;
655
656                 if (*p != ':')
657                 {
658                     err = IpAddr(token, &server_addr);
659                     if (err)
660                         return -1;
661                 }
662                 else
663                 {
664                     *p = ' ';
665                 
666                     n = sscanf(token, "%s %s", s, str_server_port);
667                     if (n != 2)
668                         return -1;
669
670                     err = IpAddr(s, &server_addr);
671                     if (err)
672                         return -1;
673                 }
674             }
675             state = STATE_READ_KEYWORD;
676             break;
677
678         case STATE_READ_RULE:
679             n = sscanf(token, "%d", &rule_index);
680             if (n != 1 || rule_index < 0)
681                 return -1;
682             state = STATE_READ_KEYWORD;
683             break;
684
685         case STATE_READ_DELETE:
686             {
687                 int err;
688                 int rule_to_delete;
689
690                 if (token_count != 2)
691                     return -1;
692
693                 n = sscanf(token, "%d", &rule_to_delete);
694                 if (n != 1)
695                     return -1;
696                 err = RuleNumberDelete(rule_to_delete);
697                 if (err)
698                     return -1;
699                 return 0;
700             }
701
702         case STATE_READ_PROTO:
703             if (strcmp(token, "tcp") == 0)
704                 proto = IPPROTO_TCP;
705             else if (strcmp(token, "udp") == 0)
706                 proto = IPPROTO_UDP;
707             else
708                 return -1;
709             state = STATE_READ_KEYWORD;
710             break;
711
712         case STATE_READ_SRC:
713         case STATE_READ_DST:
714             {
715                 int err;
716                 char *p;
717                 struct in_addr mask;
718                 struct in_addr addr;
719
720                 p = token;
721                 while (*p != '/' && *p != 0)
722                     p++;
723
724                 if (*p != '/')
725                 {
726                      IpMask(32, &mask);
727                      err = IpAddr(token, &addr);
728                      if (err)
729                          return -1;
730                 }
731                 else
732                 {
733                     int nbits;
734                     char s[sizeof(buffer)];
735
736                     *p = ' ';
737                     n = sscanf(token, "%s %d", s, &nbits);
738                     if (n != 2)
739                         return -1;
740
741                     err = IpAddr(s, &addr);
742                     if (err)
743                         return -1;
744
745                     err = IpMask(nbits, &mask);
746                     if (err)
747                         return -1;
748                 }
749
750                 if (state == STATE_READ_SRC)
751                 {
752                     src_addr = addr;
753                     src_mask = mask;
754                 }
755                 else 
756                 {
757                     dst_addr = addr;
758                     dst_mask = mask;
759                 }
760             }
761             state = STATE_READ_KEYWORD;
762             break;
763
764         default:
765             return -1;
766             break;
767         }
768
769         do {
770                 token = strsep(&res, " \t");
771         } while (token != NULL && !*token);
772     }
773 #undef STATE_READ_KEYWORD
774 #undef STATE_READ_TYPE
775 #undef STATE_READ_PORT
776 #undef STATE_READ_SERVER
777 #undef STATE_READ_RULE
778 #undef STATE_READ_DELETE
779 #undef STATE_READ_PROTO
780 #undef STATE_READ_SRC
781 #undef STATE_READ_DST
782
783 /* Convert port strings to numbers.  This needs to be done after
784    the string is parsed, because the prototype might not be designated
785    before the ports (which might be symbolic entries in /etc/services) */
786
787     if (strlen(str_port) != 0)
788     {
789         int err;
790
791         err = IpPort(str_port, proto, &proxy_port);
792         if (err)
793             return -1;
794     }
795     else
796     {
797         proxy_port = 0;
798     }
799
800     if (strlen(str_server_port) != 0)
801     { 
802         int err;
803
804         err = IpPort(str_server_port, proto, &server_port);
805         if (err)
806             return -1;
807     }
808     else
809     {
810         server_port = 0;
811     }
812
813 /* Check that at least the server address has been defined */
814     if (server_addr.s_addr == 0)
815         return -1;
816
817 /* Add to linked list */
818     proxy_entry = malloc(sizeof(struct proxy_entry));
819     if (proxy_entry == NULL)
820         return -1;
821
822     proxy_entry->proxy_type = proxy_type;
823     proxy_entry->rule_index = rule_index;
824     proxy_entry->proto = proto;
825     proxy_entry->proxy_port = htons(proxy_port);
826     proxy_entry->server_port = htons(server_port);
827     proxy_entry->server_addr = server_addr;
828     proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
829     proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
830     proxy_entry->src_mask = src_mask;
831     proxy_entry->dst_mask = dst_mask;
832
833     RuleAdd(proxy_entry);
834
835     return 0;
836 }