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