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