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