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