1f987e1bdSBrian Somers /*-
2e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <[email protected]>
3f987e1bdSBrian Somers  * All rights reserved.
4f987e1bdSBrian Somers  *
5f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
6f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
7f987e1bdSBrian Somers  * are met:
8f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
9f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
10f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
13f987e1bdSBrian Somers  *
14f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f987e1bdSBrian Somers  * SUCH DAMAGE.
25f987e1bdSBrian Somers  */
26f987e1bdSBrian Somers 
27e2505aa6SMatthew Dillon #include <sys/cdefs.h>
28e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$");
29e2505aa6SMatthew Dillon 
307d96f4efSBrian Somers /* file: alias_proxy.c
317d96f4efSBrian Somers 
327d96f4efSBrian Somers     This file encapsulates special operations related to transparent
337d96f4efSBrian Somers     proxy redirection.  This is where packets with a particular destination,
347d96f4efSBrian Somers     usually tcp port 80, are redirected to a proxy server.
357d96f4efSBrian Somers 
367d96f4efSBrian Somers     When packets are proxied, the destination address and port are
377d96f4efSBrian Somers     modified.  In certain cases, it is necessary to somehow encode
387d96f4efSBrian Somers     the original address/port info into the packet.  Two methods are
397d96f4efSBrian Somers     presently supported: addition of a [DEST addr port] string at the
409d5abbddSJens Schweikhardt     beginning of a tcp stream, or inclusion of an optional field
417d96f4efSBrian Somers     in the IP header.
427d96f4efSBrian Somers 
437d96f4efSBrian Somers     There is one public API function:
447d96f4efSBrian Somers 
457d96f4efSBrian Somers 	PacketAliasProxyRule()    -- Adds and deletes proxy
467d96f4efSBrian Somers 				     rules.
477d96f4efSBrian Somers 
487d96f4efSBrian Somers     Rules are stored in a linear linked list, so lookup efficiency
497d96f4efSBrian Somers     won't be too good for large lists.
507d96f4efSBrian Somers 
517d96f4efSBrian Somers 
527d96f4efSBrian Somers     Initial development: April, 1998 (cjm)
537d96f4efSBrian Somers */
547d96f4efSBrian Somers 
557d96f4efSBrian Somers 
567d96f4efSBrian Somers /* System includes */
57c649a2e0SGleb Smirnoff #ifdef _KERNEL
58c649a2e0SGleb Smirnoff #include <sys/param.h>
59c649a2e0SGleb Smirnoff #include <sys/ctype.h>
60c649a2e0SGleb Smirnoff #include <sys/libkern.h>
61c649a2e0SGleb Smirnoff #include <sys/limits.h>
62c649a2e0SGleb Smirnoff #else
63c649a2e0SGleb Smirnoff #include <sys/types.h>
647d96f4efSBrian Somers #include <ctype.h>
657d96f4efSBrian Somers #include <stdio.h>
667d96f4efSBrian Somers #include <stdlib.h>
677d96f4efSBrian Somers #include <netdb.h>
68be4f3cd0SPaolo Pisati #include <string.h>
69c649a2e0SGleb Smirnoff #endif
707d96f4efSBrian Somers 
717d96f4efSBrian Somers #include <netinet/tcp.h>
727d96f4efSBrian Somers 
73c649a2e0SGleb Smirnoff #ifdef _KERNEL
74c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
7575bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
76be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
77c649a2e0SGleb Smirnoff #else
78be4f3cd0SPaolo Pisati #include <arpa/inet.h>
797d96f4efSBrian Somers #include "alias.h"		/* Public API functions for libalias */
8075bc2620SGleb Smirnoff #include "alias_local.h"	/* Functions used by alias*.c */
81c649a2e0SGleb Smirnoff #endif
827d96f4efSBrian Somers 
837d96f4efSBrian Somers /*
847d96f4efSBrian Somers     Data structures
857d96f4efSBrian Somers  */
867d96f4efSBrian Somers 
877d96f4efSBrian Somers /*
887d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
897d96f4efSBrian Somers  * used to store proxy rules.
907d96f4efSBrian Somers  */
91f0f93429SDag-Erling Smørgrav struct proxy_entry {
925e289f9eSPoul-Henning Kamp 	struct libalias *la;
937d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
947d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
957d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
967d96f4efSBrian Somers 	int		rule_index;
977d96f4efSBrian Somers 	int		proxy_type;
987d96f4efSBrian Somers 	u_char		proto;
997d96f4efSBrian Somers 	u_short		proxy_port;
1007d96f4efSBrian Somers 	u_short		server_port;
1017d96f4efSBrian Somers 
1027d96f4efSBrian Somers 	struct in_addr	server_addr;
1037d96f4efSBrian Somers 
1047d96f4efSBrian Somers 	struct in_addr	src_addr;
1057d96f4efSBrian Somers 	struct in_addr	src_mask;
1067d96f4efSBrian Somers 
1077d96f4efSBrian Somers 	struct in_addr	dst_addr;
1087d96f4efSBrian Somers 	struct in_addr	dst_mask;
1097d96f4efSBrian Somers 
1107d96f4efSBrian Somers 	struct proxy_entry *next;
1117d96f4efSBrian Somers 	struct proxy_entry *last;
1127d96f4efSBrian Somers };
1137d96f4efSBrian Somers 
1147d96f4efSBrian Somers 
1157d96f4efSBrian Somers 
1167d96f4efSBrian Somers /*
1177d96f4efSBrian Somers     File scope variables
1187d96f4efSBrian Somers */
1197d96f4efSBrian Somers 
1207d96f4efSBrian Somers 
1217d96f4efSBrian Somers 
1227d96f4efSBrian Somers /* Local (static) functions:
1237d96f4efSBrian Somers 
1247d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1257d96f4efSBrian Somers 				masks from integer (1-32) specification.
1267d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1277d96f4efSBrian Somers 				to IP address
1287d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1297d96f4efSBrian Somers 				to port number
1307d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1317d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1327d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1337d96f4efSBrian Somers 				having a certain rule number.
1347d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1357d96f4efSBrian Somers 				of a TCP stream.
1367d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1377d96f4efSBrian Somers 				destination of a proxied IP packet
1387d96f4efSBrian Somers */
1397d96f4efSBrian Somers 
140e9d5db28SGleb Smirnoff #ifdef	_KERNEL		/* XXX: can it be moved to libkern? */
141e9d5db28SGleb Smirnoff static int inet_aton(const char *cp, struct in_addr *addr);
142e9d5db28SGleb Smirnoff #endif
1437d96f4efSBrian Somers static int	IpMask(int, struct in_addr *);
1447d96f4efSBrian Somers static int	IpAddr(char *, struct in_addr *);
1457d96f4efSBrian Somers static int	IpPort(char *, int, int *);
1465e289f9eSPoul-Henning Kamp static void	RuleAdd(struct libalias *la, struct proxy_entry *);
1477d96f4efSBrian Somers static void	RuleDelete(struct proxy_entry *);
1485e289f9eSPoul-Henning Kamp static int	RuleNumberDelete(struct libalias *la, int);
1497d96f4efSBrian Somers static void	ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1507d96f4efSBrian Somers static void	ProxyEncodeIpHeader(struct ip *, int);
1517d96f4efSBrian Somers 
152e9d5db28SGleb Smirnoff #ifdef	_KERNEL
153e9d5db28SGleb Smirnoff static int
154e9d5db28SGleb Smirnoff inet_aton(cp, addr)
155e9d5db28SGleb Smirnoff         const char *cp;
156e9d5db28SGleb Smirnoff         struct in_addr *addr;
157e9d5db28SGleb Smirnoff {
158e9d5db28SGleb Smirnoff 	u_long parts[4];
159e9d5db28SGleb Smirnoff 	in_addr_t val;
160e9d5db28SGleb Smirnoff 	const char *c;
161e9d5db28SGleb Smirnoff 	char *endptr;
162e9d5db28SGleb Smirnoff 	int gotend, n;
163e9d5db28SGleb Smirnoff 
164e9d5db28SGleb Smirnoff 	c = (const char *)cp;
165e9d5db28SGleb Smirnoff 	n = 0;
166e9d5db28SGleb Smirnoff 	/*
167e9d5db28SGleb Smirnoff 	 * Run through the string, grabbing numbers until
168e9d5db28SGleb Smirnoff 	 * the end of the string, or some error
169e9d5db28SGleb Smirnoff 	 */
170e9d5db28SGleb Smirnoff 	gotend = 0;
171e9d5db28SGleb Smirnoff 	while (!gotend) {
172cbfbc555SGleb Smirnoff 		unsigned long l;
173e9d5db28SGleb Smirnoff 
174cbfbc555SGleb Smirnoff 		l = strtoul(c, &endptr, 0);
175cbfbc555SGleb Smirnoff 
17638ec733cSMaxim Konovalov 		if (l == ULONG_MAX || (l == 0 && endptr == c))
177e9d5db28SGleb Smirnoff 			return (0);
178e9d5db28SGleb Smirnoff 
179cbfbc555SGleb Smirnoff 		val = (in_addr_t)l;
180e9d5db28SGleb Smirnoff 		/*
181e9d5db28SGleb Smirnoff 		 * If the whole string is invalid, endptr will equal
182e9d5db28SGleb Smirnoff 		 * c.. this way we can make sure someone hasn't
183e9d5db28SGleb Smirnoff 		 * gone '.12' or something which would get past
184e9d5db28SGleb Smirnoff 		 * the next check.
185e9d5db28SGleb Smirnoff 		 */
186e9d5db28SGleb Smirnoff 		if (endptr == c)
187e9d5db28SGleb Smirnoff 			return (0);
188e9d5db28SGleb Smirnoff 		parts[n] = val;
189e9d5db28SGleb Smirnoff 		c = endptr;
190e9d5db28SGleb Smirnoff 
191e9d5db28SGleb Smirnoff 		/* Check the next character past the previous number's end */
192e9d5db28SGleb Smirnoff 		switch (*c) {
193e9d5db28SGleb Smirnoff 		case '.' :
194e9d5db28SGleb Smirnoff 			/* Make sure we only do 3 dots .. */
195e9d5db28SGleb Smirnoff 			if (n == 3)	/* Whoops. Quit. */
196e9d5db28SGleb Smirnoff 				return (0);
197e9d5db28SGleb Smirnoff 			n++;
198e9d5db28SGleb Smirnoff 			c++;
199e9d5db28SGleb Smirnoff 			break;
200e9d5db28SGleb Smirnoff 
201e9d5db28SGleb Smirnoff 		case '\0':
202e9d5db28SGleb Smirnoff 			gotend = 1;
203e9d5db28SGleb Smirnoff 			break;
204e9d5db28SGleb Smirnoff 
205e9d5db28SGleb Smirnoff 		default:
206e9d5db28SGleb Smirnoff 			if (isspace((unsigned char)*c)) {
207e9d5db28SGleb Smirnoff 				gotend = 1;
208e9d5db28SGleb Smirnoff 				break;
209e9d5db28SGleb Smirnoff 			} else
210e9d5db28SGleb Smirnoff 				return (0);	/* Invalid character, so fail */
211e9d5db28SGleb Smirnoff 		}
212e9d5db28SGleb Smirnoff 
213e9d5db28SGleb Smirnoff 	}
214e9d5db28SGleb Smirnoff 
215e9d5db28SGleb Smirnoff 	/*
216e9d5db28SGleb Smirnoff 	 * Concoct the address according to
217e9d5db28SGleb Smirnoff 	 * the number of parts specified.
218e9d5db28SGleb Smirnoff 	 */
219e9d5db28SGleb Smirnoff 
220e9d5db28SGleb Smirnoff 	switch (n) {
221e9d5db28SGleb Smirnoff 	case 0:				/* a -- 32 bits */
222e9d5db28SGleb Smirnoff 		/*
223e9d5db28SGleb Smirnoff 		 * Nothing is necessary here.  Overflow checking was
224e9d5db28SGleb Smirnoff 		 * already done in strtoul().
225e9d5db28SGleb Smirnoff 		 */
226e9d5db28SGleb Smirnoff 		break;
227e9d5db28SGleb Smirnoff 	case 1:				/* a.b -- 8.24 bits */
228e9d5db28SGleb Smirnoff 		if (val > 0xffffff || parts[0] > 0xff)
229e9d5db28SGleb Smirnoff 			return (0);
230e9d5db28SGleb Smirnoff 		val |= parts[0] << 24;
231e9d5db28SGleb Smirnoff 		break;
232e9d5db28SGleb Smirnoff 
233e9d5db28SGleb Smirnoff 	case 2:				/* a.b.c -- 8.8.16 bits */
234e9d5db28SGleb Smirnoff 		if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
235e9d5db28SGleb Smirnoff 			return (0);
236e9d5db28SGleb Smirnoff 		val |= (parts[0] << 24) | (parts[1] << 16);
237e9d5db28SGleb Smirnoff 		break;
238e9d5db28SGleb Smirnoff 
239e9d5db28SGleb Smirnoff 	case 3:				/* a.b.c.d -- 8.8.8.8 bits */
240e9d5db28SGleb Smirnoff 		if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
241e9d5db28SGleb Smirnoff 		    parts[2] > 0xff)
242e9d5db28SGleb Smirnoff 			return (0);
243e9d5db28SGleb Smirnoff 		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
244e9d5db28SGleb Smirnoff 		break;
245e9d5db28SGleb Smirnoff 	}
246e9d5db28SGleb Smirnoff 
247e9d5db28SGleb Smirnoff 	if (addr != NULL)
248e9d5db28SGleb Smirnoff 		addr->s_addr = htonl(val);
249e9d5db28SGleb Smirnoff 	return (1);
250e9d5db28SGleb Smirnoff }
251e9d5db28SGleb Smirnoff #endif
252e9d5db28SGleb Smirnoff 
2537d96f4efSBrian Somers static int
2547d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
2557d96f4efSBrian Somers {
2567d96f4efSBrian Somers 	int i;
2577d96f4efSBrian Somers 	u_int imask;
2587d96f4efSBrian Somers 
2597d96f4efSBrian Somers 	if (nbits < 0 || nbits > 32)
260ffcb611aSDag-Erling Smørgrav 		return (-1);
2617d96f4efSBrian Somers 
2627d96f4efSBrian Somers 	imask = 0;
2637d96f4efSBrian Somers 	for (i = 0; i < nbits; i++)
2647d96f4efSBrian Somers 		imask = (imask >> 1) + 0x80000000;
2657d96f4efSBrian Somers 	mask->s_addr = htonl(imask);
2667d96f4efSBrian Somers 
267ffcb611aSDag-Erling Smørgrav 	return (0);
2687d96f4efSBrian Somers }
2697d96f4efSBrian Somers 
2707d96f4efSBrian Somers static int
2717d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
2727d96f4efSBrian Somers {
2737d96f4efSBrian Somers 	if (inet_aton(s, addr) == 0)
274ffcb611aSDag-Erling Smørgrav 		return (-1);
2757d96f4efSBrian Somers 	else
276ffcb611aSDag-Erling Smørgrav 		return (0);
2777d96f4efSBrian Somers }
2787d96f4efSBrian Somers 
2797d96f4efSBrian Somers static int
2807d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
2817d96f4efSBrian Somers {
2827d96f4efSBrian Somers 	int n;
2837d96f4efSBrian Somers 
2847d96f4efSBrian Somers 	n = sscanf(s, "%d", port);
285e9d5db28SGleb Smirnoff 	if (n != 1)
286e9d5db28SGleb Smirnoff #ifndef _KERNEL	/* XXX: we accept only numeric ports in kernel */
287e9d5db28SGleb Smirnoff 	{
2887d96f4efSBrian Somers 		struct servent *se;
2897d96f4efSBrian Somers 
2907d96f4efSBrian Somers 		if (proto == IPPROTO_TCP)
2917d96f4efSBrian Somers 			se = getservbyname(s, "tcp");
2927d96f4efSBrian Somers 		else if (proto == IPPROTO_UDP)
2937d96f4efSBrian Somers 			se = getservbyname(s, "udp");
2947d96f4efSBrian Somers 		else
295ffcb611aSDag-Erling Smørgrav 			return (-1);
2967d96f4efSBrian Somers 
2977d96f4efSBrian Somers 		if (se == NULL)
298ffcb611aSDag-Erling Smørgrav 			return (-1);
2997d96f4efSBrian Somers 
3007d96f4efSBrian Somers 		*port = (u_int) ntohs(se->s_port);
3017d96f4efSBrian Somers 	}
302e9d5db28SGleb Smirnoff #else
303e9d5db28SGleb Smirnoff 		return (-1);
304e9d5db28SGleb Smirnoff #endif
305ffcb611aSDag-Erling Smørgrav 	return (0);
3067d96f4efSBrian Somers }
3077d96f4efSBrian Somers 
3087d96f4efSBrian Somers void
3095e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
3107d96f4efSBrian Somers {
3117d96f4efSBrian Somers 	int rule_index;
3127d96f4efSBrian Somers 	struct proxy_entry *ptr;
3137d96f4efSBrian Somers 	struct proxy_entry *ptr_last;
3147d96f4efSBrian Somers 
315ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
316ccd57eeaSPaolo Pisati 
317f0f93429SDag-Erling Smørgrav 	if (la->proxyList == NULL) {
3185e289f9eSPoul-Henning Kamp 		la->proxyList = entry;
3197d96f4efSBrian Somers 		entry->last = NULL;
3207d96f4efSBrian Somers 		entry->next = NULL;
3217d96f4efSBrian Somers 		return;
3227d96f4efSBrian Somers 	}
3235e289f9eSPoul-Henning Kamp 	entry->la = la;
3247d96f4efSBrian Somers 
3257d96f4efSBrian Somers 	rule_index = entry->rule_index;
3265e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
3277d96f4efSBrian Somers 	ptr_last = NULL;
328f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
329f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index >= rule_index) {
330f0f93429SDag-Erling Smørgrav 			if (ptr_last == NULL) {
3315e289f9eSPoul-Henning Kamp 				entry->next = la->proxyList;
3327d96f4efSBrian Somers 				entry->last = NULL;
3335e289f9eSPoul-Henning Kamp 				la->proxyList->last = entry;
3345e289f9eSPoul-Henning Kamp 				la->proxyList = entry;
3357d96f4efSBrian Somers 				return;
3367d96f4efSBrian Somers 			}
3377d96f4efSBrian Somers 			ptr_last->next = entry;
3387d96f4efSBrian Somers 			ptr->last = entry;
3397d96f4efSBrian Somers 			entry->last = ptr->last;
3407d96f4efSBrian Somers 			entry->next = ptr;
3417d96f4efSBrian Somers 			return;
3427d96f4efSBrian Somers 		}
3437d96f4efSBrian Somers 		ptr_last = ptr;
3447d96f4efSBrian Somers 		ptr = ptr->next;
3457d96f4efSBrian Somers 	}
3467d96f4efSBrian Somers 
3477d96f4efSBrian Somers 	ptr_last->next = entry;
3487d96f4efSBrian Somers 	entry->last = ptr_last;
3497d96f4efSBrian Somers 	entry->next = NULL;
3507d96f4efSBrian Somers }
3517d96f4efSBrian Somers 
3527d96f4efSBrian Somers static void
3537d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
3547d96f4efSBrian Somers {
3555e289f9eSPoul-Henning Kamp 	struct libalias *la;
3565e289f9eSPoul-Henning Kamp 
3575e289f9eSPoul-Henning Kamp 	la = entry->la;
358ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
3597d96f4efSBrian Somers 	if (entry->last != NULL)
3607d96f4efSBrian Somers 		entry->last->next = entry->next;
3617d96f4efSBrian Somers 	else
3625e289f9eSPoul-Henning Kamp 		la->proxyList = entry->next;
3637d96f4efSBrian Somers 
3647d96f4efSBrian Somers 	if (entry->next != NULL)
3657d96f4efSBrian Somers 		entry->next->last = entry->last;
3667d96f4efSBrian Somers 
3677d96f4efSBrian Somers 	free(entry);
3687d96f4efSBrian Somers }
3697d96f4efSBrian Somers 
3707d96f4efSBrian Somers static int
3715e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
3727d96f4efSBrian Somers {
3737d96f4efSBrian Somers 	int err;
3747d96f4efSBrian Somers 	struct proxy_entry *ptr;
3757d96f4efSBrian Somers 
376ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
3777d96f4efSBrian Somers 	err = -1;
3785e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
379f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
3807d96f4efSBrian Somers 		struct proxy_entry *ptr_next;
3817d96f4efSBrian Somers 
3827d96f4efSBrian Somers 		ptr_next = ptr->next;
383f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index == rule_index) {
3847d96f4efSBrian Somers 			err = 0;
3857d96f4efSBrian Somers 			RuleDelete(ptr);
3867d96f4efSBrian Somers 		}
3877d96f4efSBrian Somers 		ptr = ptr_next;
3887d96f4efSBrian Somers 	}
3897d96f4efSBrian Somers 
390ffcb611aSDag-Erling Smørgrav 	return (err);
3917d96f4efSBrian Somers }
3927d96f4efSBrian Somers 
3937d96f4efSBrian Somers static void
394ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk,
3957d96f4efSBrian Somers     struct ip *pip,
3967d96f4efSBrian Somers     int maxpacketsize)
3977d96f4efSBrian Somers {
3987d96f4efSBrian Somers 	int slen;
3997d96f4efSBrian Somers 	char buffer[40];
4007d96f4efSBrian Somers 	struct tcphdr *tc;
4017d96f4efSBrian Somers 
4027d96f4efSBrian Somers /* Compute pointer to tcp header */
4039fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
4047d96f4efSBrian Somers 
4057d96f4efSBrian Somers /* Don't modify if once already modified */
4067d96f4efSBrian Somers 
407ed01a582SDag-Erling Smørgrav 	if (GetAckModified(lnk))
4087d96f4efSBrian Somers 		return;
4097d96f4efSBrian Somers 
4107d96f4efSBrian Somers /* Translate destination address and port to string form */
4117d96f4efSBrian Somers 	snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
412ed01a582SDag-Erling Smørgrav 	    inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
4137d96f4efSBrian Somers 
4147d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
4157d96f4efSBrian Somers 	slen = strlen(buffer);
416f0f93429SDag-Erling Smørgrav 	switch (slen % 2) {
4177d96f4efSBrian Somers 	case 0:
4187d96f4efSBrian Somers 		strcat(buffer, " \n");
4197d96f4efSBrian Somers 		slen += 2;
4207d96f4efSBrian Somers 		break;
4217d96f4efSBrian Somers 	case 1:
4227d96f4efSBrian Somers 		strcat(buffer, "\n");
4237d96f4efSBrian Somers 		slen += 1;
4247d96f4efSBrian Somers 	}
4257d96f4efSBrian Somers 
4267d96f4efSBrian Somers /* Check for packet overflow */
427ed01a582SDag-Erling Smørgrav 	if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
4287d96f4efSBrian Somers 		return;
4297d96f4efSBrian Somers 
4307d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
4317d96f4efSBrian Somers 	{
4327d96f4efSBrian Somers 		int dlen;
4337d96f4efSBrian Somers 		int hlen;
4349160afeeSAlexander Kabaev 		char *p;
4357d96f4efSBrian Somers 
4367d96f4efSBrian Somers 		hlen = (pip->ip_hl + tc->th_off) << 2;
4377d96f4efSBrian Somers 		dlen = ntohs(pip->ip_len) - hlen;
4387d96f4efSBrian Somers 
4397d96f4efSBrian Somers /* Modify first packet that has data in it */
4407d96f4efSBrian Somers 
4417d96f4efSBrian Somers 		if (dlen == 0)
4427d96f4efSBrian Somers 			return;
4437d96f4efSBrian Somers 
4447d96f4efSBrian Somers 		p = (char *)pip;
4457d96f4efSBrian Somers 		p += hlen;
4467d96f4efSBrian Somers 
447c8d3ca72SGleb Smirnoff 		bcopy(p, p + slen, dlen);
4487d96f4efSBrian Somers 		memcpy(p, buffer, slen);
4497d96f4efSBrian Somers 	}
4507d96f4efSBrian Somers 
4517d96f4efSBrian Somers /* Save information about modfied sequence number */
4527d96f4efSBrian Somers 	{
4537d96f4efSBrian Somers 		int delta;
4547d96f4efSBrian Somers 
455ed01a582SDag-Erling Smørgrav 		SetAckModified(lnk);
456*4741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
457*4741f3a1SPaolo Pisati 		delta = GetDeltaSeqOut(tc->th_seq, lnk);
458*4741f3a1SPaolo Pisati 		AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
459*4741f3a1SPaolo Pisati 		    tc->th_off);
4607d96f4efSBrian Somers 	}
4617d96f4efSBrian Somers 
4627d96f4efSBrian Somers /* Update IP header packet length and checksum */
4637d96f4efSBrian Somers 	{
4647d96f4efSBrian Somers 		int accumulate;
4657d96f4efSBrian Somers 
4667d96f4efSBrian Somers 		accumulate = pip->ip_len;
4677d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + slen);
4687d96f4efSBrian Somers 		accumulate -= pip->ip_len;
4697d96f4efSBrian Somers 
4707d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4717d96f4efSBrian Somers 	}
4727d96f4efSBrian Somers 
4737d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
4747d96f4efSBrian Somers    already changed. */
4757d96f4efSBrian Somers 
4767d96f4efSBrian Somers 	tc->th_sum = 0;
47759dde15eSGleb Smirnoff #ifdef _KERNEL
47859dde15eSGleb Smirnoff 	tc->th_x2 = 1;
47959dde15eSGleb Smirnoff #else
4807d96f4efSBrian Somers 	tc->th_sum = TcpChecksum(pip);
48159dde15eSGleb Smirnoff #endif
4827d96f4efSBrian Somers }
4837d96f4efSBrian Somers 
4847d96f4efSBrian Somers static void
4857d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
4867d96f4efSBrian Somers     int maxpacketsize)
4877d96f4efSBrian Somers {
4887d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
4897d96f4efSBrian Somers #define OPTION_LEN_INT16  4
4907d96f4efSBrian Somers #define OPTION_LEN_INT32  2
4917d96f4efSBrian Somers 	u_char option[OPTION_LEN_BYTES];
4927d96f4efSBrian Somers 
4936293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
4947d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
4957d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
4964c32f5d2SBrian Somers #endif
4977d96f4efSBrian Somers 
498ed01a582SDag-Erling Smørgrav 	(void)maxpacketsize;
499ed01a582SDag-Erling Smørgrav 
5007d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
5017d96f4efSBrian Somers 	if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
5027d96f4efSBrian Somers 		return;
5037d96f4efSBrian Somers 
5047d96f4efSBrian Somers /* Build option and copy into packet */
5057d96f4efSBrian Somers 	{
5067d96f4efSBrian Somers 		u_char *ptr;
5077d96f4efSBrian Somers 		struct tcphdr *tc;
5087d96f4efSBrian Somers 
5097d96f4efSBrian Somers 		ptr = (u_char *) pip;
5107d96f4efSBrian Somers 		ptr += 20;
5117d96f4efSBrian Somers 		memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
5127d96f4efSBrian Somers 
5137d96f4efSBrian Somers 		option[0] = 0x64;	/* class: 3 (reserved), option 4 */
5147d96f4efSBrian Somers 		option[1] = OPTION_LEN_BYTES;
5157d96f4efSBrian Somers 
5167d96f4efSBrian Somers 		memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
5177d96f4efSBrian Somers 
5189fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
5197d96f4efSBrian Somers 		memcpy(&option[6], (u_char *) & tc->th_sport, 2);
5207d96f4efSBrian Somers 
5217d96f4efSBrian Somers 		memcpy(ptr, option, 8);
5227d96f4efSBrian Somers 	}
5237d96f4efSBrian Somers 
5247d96f4efSBrian Somers /* Update checksum, header length and packet length */
5257d96f4efSBrian Somers 	{
5267d96f4efSBrian Somers 		int i;
5277d96f4efSBrian Somers 		int accumulate;
5287d96f4efSBrian Somers 		u_short *sptr;
5297d96f4efSBrian Somers 
5307d96f4efSBrian Somers 		sptr = (u_short *) option;
5317d96f4efSBrian Somers 		accumulate = 0;
5327d96f4efSBrian Somers 		for (i = 0; i < OPTION_LEN_INT16; i++)
5337d96f4efSBrian Somers 			accumulate -= *(sptr++);
5347d96f4efSBrian Somers 
5357d96f4efSBrian Somers 		sptr = (u_short *) pip;
5367d96f4efSBrian Somers 		accumulate += *sptr;
5377d96f4efSBrian Somers 		pip->ip_hl += OPTION_LEN_INT32;
5387d96f4efSBrian Somers 		accumulate -= *sptr;
5397d96f4efSBrian Somers 
5407d96f4efSBrian Somers 		accumulate += pip->ip_len;
5417d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
5427d96f4efSBrian Somers 		accumulate -= pip->ip_len;
5437d96f4efSBrian Somers 
5447d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
5457d96f4efSBrian Somers 	}
5467d96f4efSBrian Somers #undef OPTION_LEN_BYTES
5477d96f4efSBrian Somers #undef OPTION_LEN_INT16
5487d96f4efSBrian Somers #undef OPTION_LEN_INT32
5496293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
5507d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
5517d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
5524c32f5d2SBrian Somers #endif
5537d96f4efSBrian Somers }
5547d96f4efSBrian Somers 
5557d96f4efSBrian Somers 
5567d96f4efSBrian Somers /* Functions by other packet alias source files
5577d96f4efSBrian Somers 
5587d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
5597d96f4efSBrian Somers 			    be proxied.
5607d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
5617d96f4efSBrian Somers 			    for a packet which is to be redirected to
5627d96f4efSBrian Somers 			    a proxy server.
5637d96f4efSBrian Somers */
5647d96f4efSBrian Somers 
5657d96f4efSBrian Somers int
566*4741f3a1SPaolo Pisati ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
567*4741f3a1SPaolo Pisati     u_short * proxy_server_port, struct in_addr src_addr,
568*4741f3a1SPaolo Pisati     struct in_addr dst_addr, u_short dst_port, u_char ip_p)
5697d96f4efSBrian Somers {
5707d96f4efSBrian Somers 	struct proxy_entry *ptr;
5717d96f4efSBrian Somers 
572ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
5737d96f4efSBrian Somers 
5745e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
575f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
5767d96f4efSBrian Somers 		u_short proxy_port;
5777d96f4efSBrian Somers 
5787d96f4efSBrian Somers 		proxy_port = ptr->proxy_port;
5797d96f4efSBrian Somers 		if ((dst_port == proxy_port || proxy_port == 0)
580*4741f3a1SPaolo Pisati 		    && ip_p == ptr->proto
581f0f93429SDag-Erling Smørgrav 		    && src_addr.s_addr != ptr->server_addr.s_addr) {
5827d96f4efSBrian Somers 			struct in_addr src_addr_masked;
5837d96f4efSBrian Somers 			struct in_addr dst_addr_masked;
5847d96f4efSBrian Somers 
5857d96f4efSBrian Somers 			src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
5867d96f4efSBrian Somers 			dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
5877d96f4efSBrian Somers 
5887d96f4efSBrian Somers 			if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
589f0f93429SDag-Erling Smørgrav 			    && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
5907d96f4efSBrian Somers 				if ((*proxy_server_port = ptr->server_port) == 0)
5917d96f4efSBrian Somers 					*proxy_server_port = dst_port;
5927d96f4efSBrian Somers 				*proxy_server_addr = ptr->server_addr;
593ffcb611aSDag-Erling Smørgrav 				return (ptr->proxy_type);
5947d96f4efSBrian Somers 			}
5957d96f4efSBrian Somers 		}
5967d96f4efSBrian Somers 		ptr = ptr->next;
5977d96f4efSBrian Somers 	}
5987d96f4efSBrian Somers 
599ffcb611aSDag-Erling Smørgrav 	return (0);
6007d96f4efSBrian Somers }
6017d96f4efSBrian Somers 
6027d96f4efSBrian Somers void
603ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk,
6047d96f4efSBrian Somers     struct ip *pip,
6057d96f4efSBrian Somers     int maxpacketsize,
6067d96f4efSBrian Somers     int proxy_type)
6077d96f4efSBrian Somers {
608ed01a582SDag-Erling Smørgrav 
609ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
610ed01a582SDag-Erling Smørgrav 	(void)la;
611ed01a582SDag-Erling Smørgrav 
612f0f93429SDag-Erling Smørgrav 	switch (proxy_type) {
6137d96f4efSBrian Somers 		case PROXY_TYPE_ENCODE_IPHDR:
6147d96f4efSBrian Somers 		ProxyEncodeIpHeader(pip, maxpacketsize);
6157d96f4efSBrian Somers 		break;
6167d96f4efSBrian Somers 
6177d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_TCPSTREAM:
618ed01a582SDag-Erling Smørgrav 		ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
6197d96f4efSBrian Somers 		break;
6207d96f4efSBrian Somers 	}
6217d96f4efSBrian Somers }
6227d96f4efSBrian Somers 
6237d96f4efSBrian Somers 
6247d96f4efSBrian Somers /*
6257d96f4efSBrian Somers     Public API functions
6267d96f4efSBrian Somers */
6277d96f4efSBrian Somers 
6287d96f4efSBrian Somers int
6295e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd)
6307d96f4efSBrian Somers {
6317d96f4efSBrian Somers /*
6327d96f4efSBrian Somers  * This function takes command strings of the form:
6337d96f4efSBrian Somers  *
6347d96f4efSBrian Somers  *   server <addr>[:<port>]
6357d96f4efSBrian Somers  *   [port <port>]
6367d96f4efSBrian Somers  *   [rule n]
6377d96f4efSBrian Somers  *   [proto tcp|udp]
6387d96f4efSBrian Somers  *   [src <addr>[/n]]
6397d96f4efSBrian Somers  *   [dst <addr>[/n]]
6407d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
6417d96f4efSBrian Somers  *
6427d96f4efSBrian Somers  *   delete <rule number>
6437d96f4efSBrian Somers  *
6447d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
6457d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
6467d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
6477d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
6487d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
6497d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
6507d96f4efSBrian Somers  * others.
6517d96f4efSBrian Somers  */
652ccd57eeaSPaolo Pisati 	int i, n, len, ret;
6537d96f4efSBrian Somers 	int cmd_len;
6547d96f4efSBrian Somers 	int token_count;
6557d96f4efSBrian Somers 	int state;
6567d96f4efSBrian Somers 	char *token;
6577d96f4efSBrian Somers 	char buffer[256];
6587d96f4efSBrian Somers 	char str_port[sizeof(buffer)];
6597d96f4efSBrian Somers 	char str_server_port[sizeof(buffer)];
660d9e630b5SAndrey A. Chernov 	char *res = buffer;
6617d96f4efSBrian Somers 
6627d96f4efSBrian Somers 	int rule_index;
6637d96f4efSBrian Somers 	int proto;
6647d96f4efSBrian Somers 	int proxy_type;
6657d96f4efSBrian Somers 	int proxy_port;
6667d96f4efSBrian Somers 	int server_port;
6677d96f4efSBrian Somers 	struct in_addr server_addr;
6687d96f4efSBrian Somers 	struct in_addr src_addr, src_mask;
6697d96f4efSBrian Somers 	struct in_addr dst_addr, dst_mask;
6707d96f4efSBrian Somers 	struct proxy_entry *proxy_entry;
6717d96f4efSBrian Somers 
672ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
673ccd57eeaSPaolo Pisati 	ret = 0;
6747d96f4efSBrian Somers /* Copy command line into a buffer */
6754834b77dSBrian Somers 	cmd += strspn(cmd, " \t");
6767d96f4efSBrian Somers 	cmd_len = strlen(cmd);
677ccd57eeaSPaolo Pisati 	if (cmd_len > (int)(sizeof(buffer) - 1)) {
678ccd57eeaSPaolo Pisati 		ret = -1;
679ccd57eeaSPaolo Pisati 		goto getout;
680ccd57eeaSPaolo Pisati 	}
6817d96f4efSBrian Somers 	strcpy(buffer, cmd);
6827d96f4efSBrian Somers 
6837d96f4efSBrian Somers /* Convert to lower case */
6847d96f4efSBrian Somers 	len = strlen(buffer);
6857d96f4efSBrian Somers 	for (i = 0; i < len; i++)
686d9e630b5SAndrey A. Chernov 		buffer[i] = tolower((unsigned char)buffer[i]);
6877d96f4efSBrian Somers 
6887d96f4efSBrian Somers /* Set default proxy type */
6897d96f4efSBrian Somers 
6907d96f4efSBrian Somers /* Set up default values */
6917d96f4efSBrian Somers 	rule_index = 0;
6927d96f4efSBrian Somers 	proxy_type = PROXY_TYPE_ENCODE_NONE;
6937d96f4efSBrian Somers 	proto = IPPROTO_TCP;
6947d96f4efSBrian Somers 	proxy_port = 0;
6957d96f4efSBrian Somers 	server_addr.s_addr = 0;
6967d96f4efSBrian Somers 	server_port = 0;
6977d96f4efSBrian Somers 	src_addr.s_addr = 0;
6987d96f4efSBrian Somers 	IpMask(0, &src_mask);
6997d96f4efSBrian Somers 	dst_addr.s_addr = 0;
7007d96f4efSBrian Somers 	IpMask(0, &dst_mask);
7017d96f4efSBrian Somers 
7027d96f4efSBrian Somers 	str_port[0] = 0;
7037d96f4efSBrian Somers 	str_server_port[0] = 0;
7047d96f4efSBrian Somers 
7057d96f4efSBrian Somers /* Parse command string with state machine */
7067d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
7077d96f4efSBrian Somers #define STATE_READ_TYPE       1
7087d96f4efSBrian Somers #define STATE_READ_PORT       2
7097d96f4efSBrian Somers #define STATE_READ_SERVER     3
7107d96f4efSBrian Somers #define STATE_READ_RULE       4
7117d96f4efSBrian Somers #define STATE_READ_DELETE     5
7127d96f4efSBrian Somers #define STATE_READ_PROTO      6
7137d96f4efSBrian Somers #define STATE_READ_SRC        7
7147d96f4efSBrian Somers #define STATE_READ_DST        8
7157d96f4efSBrian Somers 	state = STATE_READ_KEYWORD;
716d9e630b5SAndrey A. Chernov 	token = strsep(&res, " \t");
7177d96f4efSBrian Somers 	token_count = 0;
718f0f93429SDag-Erling Smørgrav 	while (token != NULL) {
7197d96f4efSBrian Somers 		token_count++;
720f0f93429SDag-Erling Smørgrav 		switch (state) {
7217d96f4efSBrian Somers 		case STATE_READ_KEYWORD:
7227d96f4efSBrian Somers 			if (strcmp(token, "type") == 0)
7237d96f4efSBrian Somers 				state = STATE_READ_TYPE;
7247d96f4efSBrian Somers 			else if (strcmp(token, "port") == 0)
7257d96f4efSBrian Somers 				state = STATE_READ_PORT;
7267d96f4efSBrian Somers 			else if (strcmp(token, "server") == 0)
7277d96f4efSBrian Somers 				state = STATE_READ_SERVER;
7287d96f4efSBrian Somers 			else if (strcmp(token, "rule") == 0)
7297d96f4efSBrian Somers 				state = STATE_READ_RULE;
7307d96f4efSBrian Somers 			else if (strcmp(token, "delete") == 0)
7317d96f4efSBrian Somers 				state = STATE_READ_DELETE;
7327d96f4efSBrian Somers 			else if (strcmp(token, "proto") == 0)
7337d96f4efSBrian Somers 				state = STATE_READ_PROTO;
7347d96f4efSBrian Somers 			else if (strcmp(token, "src") == 0)
7357d96f4efSBrian Somers 				state = STATE_READ_SRC;
7367d96f4efSBrian Somers 			else if (strcmp(token, "dst") == 0)
7377d96f4efSBrian Somers 				state = STATE_READ_DST;
738ccd57eeaSPaolo Pisati 			else {
739ccd57eeaSPaolo Pisati 				ret = -1;
740ccd57eeaSPaolo Pisati 				goto getout;
741ccd57eeaSPaolo Pisati 			}
7427d96f4efSBrian Somers 			break;
7437d96f4efSBrian Somers 
7447d96f4efSBrian Somers 		case STATE_READ_TYPE:
7457d96f4efSBrian Somers 			if (strcmp(token, "encode_ip_hdr") == 0)
7467d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_IPHDR;
7477d96f4efSBrian Somers 			else if (strcmp(token, "encode_tcp_stream") == 0)
7487d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
7497d96f4efSBrian Somers 			else if (strcmp(token, "no_encode") == 0)
7507d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_NONE;
751ccd57eeaSPaolo Pisati 			else {
752ccd57eeaSPaolo Pisati 				ret = -1;
753ccd57eeaSPaolo Pisati 				goto getout;
754ccd57eeaSPaolo Pisati 			}
7557d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7567d96f4efSBrian Somers 			break;
7577d96f4efSBrian Somers 
7587d96f4efSBrian Somers 		case STATE_READ_PORT:
7597d96f4efSBrian Somers 			strcpy(str_port, token);
7607d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7617d96f4efSBrian Somers 			break;
7627d96f4efSBrian Somers 
7637d96f4efSBrian Somers 		case STATE_READ_SERVER:
7647d96f4efSBrian Somers 			{
7657d96f4efSBrian Somers 				int err;
7667d96f4efSBrian Somers 				char *p;
7677d96f4efSBrian Somers 				char s[sizeof(buffer)];
7687d96f4efSBrian Somers 
7697d96f4efSBrian Somers 				p = token;
7707d96f4efSBrian Somers 				while (*p != ':' && *p != 0)
7717d96f4efSBrian Somers 					p++;
7727d96f4efSBrian Somers 
773f0f93429SDag-Erling Smørgrav 				if (*p != ':') {
7747d96f4efSBrian Somers 					err = IpAddr(token, &server_addr);
775ccd57eeaSPaolo Pisati 					if (err) {
776ccd57eeaSPaolo Pisati 						ret = -1;
777ccd57eeaSPaolo Pisati 						goto getout;
778ccd57eeaSPaolo Pisati 					}
779f0f93429SDag-Erling Smørgrav 				} else {
7807d96f4efSBrian Somers 					*p = ' ';
7817d96f4efSBrian Somers 
7827d96f4efSBrian Somers 					n = sscanf(token, "%s %s", s, str_server_port);
783ccd57eeaSPaolo Pisati 					if (n != 2) {
784ccd57eeaSPaolo Pisati 						ret = -1;
785ccd57eeaSPaolo Pisati 						goto getout;
786ccd57eeaSPaolo Pisati 					}
7877d96f4efSBrian Somers 
7887d96f4efSBrian Somers 					err = IpAddr(s, &server_addr);
789ccd57eeaSPaolo Pisati 					if (err) {
790ccd57eeaSPaolo Pisati 						ret = -1;
791ccd57eeaSPaolo Pisati 						goto getout;
792ccd57eeaSPaolo Pisati 					}
7937d96f4efSBrian Somers 				}
7947d96f4efSBrian Somers 			}
7957d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7967d96f4efSBrian Somers 			break;
7977d96f4efSBrian Somers 
7987d96f4efSBrian Somers 		case STATE_READ_RULE:
7997d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_index);
800ccd57eeaSPaolo Pisati 			if (n != 1 || rule_index < 0) {
801ccd57eeaSPaolo Pisati 				ret = -1;
802ccd57eeaSPaolo Pisati 				goto getout;
803ccd57eeaSPaolo Pisati 			}
8047d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
8057d96f4efSBrian Somers 			break;
8067d96f4efSBrian Somers 
8077d96f4efSBrian Somers 		case STATE_READ_DELETE:
8087d96f4efSBrian Somers 			{
8097d96f4efSBrian Somers 				int err;
8107d96f4efSBrian Somers 				int rule_to_delete;
8117d96f4efSBrian Somers 
812ccd57eeaSPaolo Pisati 				if (token_count != 2) {
813ccd57eeaSPaolo Pisati 					ret = -1;
814ccd57eeaSPaolo Pisati 					goto getout;
815ccd57eeaSPaolo Pisati 				}
8167d96f4efSBrian Somers 
8177d96f4efSBrian Somers 				n = sscanf(token, "%d", &rule_to_delete);
818ccd57eeaSPaolo Pisati 				if (n != 1) {
819ccd57eeaSPaolo Pisati 					ret = -1;
820ccd57eeaSPaolo Pisati 					goto getout;
821ccd57eeaSPaolo Pisati 				}
8225e289f9eSPoul-Henning Kamp 				err = RuleNumberDelete(la, rule_to_delete);
8237d96f4efSBrian Somers 				if (err)
824ccd57eeaSPaolo Pisati 					ret = -1;
825ccd57eeaSPaolo Pisati 				ret = 0;
826ccd57eeaSPaolo Pisati 				goto getout;
8277d96f4efSBrian Somers 			}
8287d96f4efSBrian Somers 
8297d96f4efSBrian Somers 		case STATE_READ_PROTO:
8307d96f4efSBrian Somers 			if (strcmp(token, "tcp") == 0)
8317d96f4efSBrian Somers 				proto = IPPROTO_TCP;
8327d96f4efSBrian Somers 			else if (strcmp(token, "udp") == 0)
8337d96f4efSBrian Somers 				proto = IPPROTO_UDP;
834ccd57eeaSPaolo Pisati 			else {
835ccd57eeaSPaolo Pisati 				ret = -1;
836ccd57eeaSPaolo Pisati 				goto getout;
837ccd57eeaSPaolo Pisati 			}
8387d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
8397d96f4efSBrian Somers 			break;
8407d96f4efSBrian Somers 
8417d96f4efSBrian Somers 		case STATE_READ_SRC:
8427d96f4efSBrian Somers 		case STATE_READ_DST:
8437d96f4efSBrian Somers 			{
8447d96f4efSBrian Somers 				int err;
8457d96f4efSBrian Somers 				char *p;
8467d96f4efSBrian Somers 				struct in_addr mask;
8477d96f4efSBrian Somers 				struct in_addr addr;
8487d96f4efSBrian Somers 
8497d96f4efSBrian Somers 				p = token;
8507d96f4efSBrian Somers 				while (*p != '/' && *p != 0)
8517d96f4efSBrian Somers 					p++;
8527d96f4efSBrian Somers 
853f0f93429SDag-Erling Smørgrav 				if (*p != '/') {
8547d96f4efSBrian Somers 					IpMask(32, &mask);
8557d96f4efSBrian Somers 					err = IpAddr(token, &addr);
856ccd57eeaSPaolo Pisati 					if (err) {
857ccd57eeaSPaolo Pisati 						ret = -1;
858ccd57eeaSPaolo Pisati 						goto getout;
859ccd57eeaSPaolo Pisati 					}
860f0f93429SDag-Erling Smørgrav 				} else {
8617d96f4efSBrian Somers 					int nbits;
8627d96f4efSBrian Somers 					char s[sizeof(buffer)];
8637d96f4efSBrian Somers 
8647d96f4efSBrian Somers 					*p = ' ';
8657d96f4efSBrian Somers 					n = sscanf(token, "%s %d", s, &nbits);
866ccd57eeaSPaolo Pisati 					if (n != 2) {
867ccd57eeaSPaolo Pisati 						ret = -1;
868ccd57eeaSPaolo Pisati 						goto getout;
869ccd57eeaSPaolo Pisati 					}
8707d96f4efSBrian Somers 
8717d96f4efSBrian Somers 					err = IpAddr(s, &addr);
872ccd57eeaSPaolo Pisati 					if (err) {
873ccd57eeaSPaolo Pisati 						ret = -1;
874ccd57eeaSPaolo Pisati 						goto getout;
875ccd57eeaSPaolo Pisati 					}
8767d96f4efSBrian Somers 
8777d96f4efSBrian Somers 					err = IpMask(nbits, &mask);
878ccd57eeaSPaolo Pisati 					if (err) {
879ccd57eeaSPaolo Pisati 						ret = -1;
880ccd57eeaSPaolo Pisati 						goto getout;
881ccd57eeaSPaolo Pisati 					}
8827d96f4efSBrian Somers 				}
8837d96f4efSBrian Somers 
884f0f93429SDag-Erling Smørgrav 				if (state == STATE_READ_SRC) {
8857d96f4efSBrian Somers 					src_addr = addr;
8867d96f4efSBrian Somers 					src_mask = mask;
887f0f93429SDag-Erling Smørgrav 				} else {
8887d96f4efSBrian Somers 					dst_addr = addr;
8897d96f4efSBrian Somers 					dst_mask = mask;
8907d96f4efSBrian Somers 				}
8917d96f4efSBrian Somers 			}
8927d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
8937d96f4efSBrian Somers 			break;
8947d96f4efSBrian Somers 
8957d96f4efSBrian Somers 		default:
896ccd57eeaSPaolo Pisati 			ret = -1;
897ccd57eeaSPaolo Pisati 			goto getout;
8987d96f4efSBrian Somers 			break;
8997d96f4efSBrian Somers 		}
9007d96f4efSBrian Somers 
901d9e630b5SAndrey A. Chernov 		do {
902d9e630b5SAndrey A. Chernov 			token = strsep(&res, " \t");
903d9e630b5SAndrey A. Chernov 		} while (token != NULL && !*token);
9047d96f4efSBrian Somers 	}
9057d96f4efSBrian Somers #undef STATE_READ_KEYWORD
9067d96f4efSBrian Somers #undef STATE_READ_TYPE
9077d96f4efSBrian Somers #undef STATE_READ_PORT
9087d96f4efSBrian Somers #undef STATE_READ_SERVER
9097d96f4efSBrian Somers #undef STATE_READ_RULE
9107d96f4efSBrian Somers #undef STATE_READ_DELETE
9117d96f4efSBrian Somers #undef STATE_READ_PROTO
9127d96f4efSBrian Somers #undef STATE_READ_SRC
9137d96f4efSBrian Somers #undef STATE_READ_DST
9147d96f4efSBrian Somers 
9157d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
9167d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
9177d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
9187d96f4efSBrian Somers 
919f0f93429SDag-Erling Smørgrav 	if (strlen(str_port) != 0) {
9207d96f4efSBrian Somers 		int err;
9217d96f4efSBrian Somers 
9227d96f4efSBrian Somers 		err = IpPort(str_port, proto, &proxy_port);
923ccd57eeaSPaolo Pisati 		if (err) {
924ccd57eeaSPaolo Pisati 			ret = -1;
925ccd57eeaSPaolo Pisati 			goto getout;
926ccd57eeaSPaolo Pisati 		}
927f0f93429SDag-Erling Smørgrav 	} else {
9287d96f4efSBrian Somers 		proxy_port = 0;
9297d96f4efSBrian Somers 	}
9307d96f4efSBrian Somers 
931f0f93429SDag-Erling Smørgrav 	if (strlen(str_server_port) != 0) {
9327d96f4efSBrian Somers 		int err;
9337d96f4efSBrian Somers 
9347d96f4efSBrian Somers 		err = IpPort(str_server_port, proto, &server_port);
935ccd57eeaSPaolo Pisati 		if (err) {
936ccd57eeaSPaolo Pisati 			ret = -1;
937ccd57eeaSPaolo Pisati 			goto getout;
938ccd57eeaSPaolo Pisati 		}
939f0f93429SDag-Erling Smørgrav 	} else {
9407d96f4efSBrian Somers 		server_port = 0;
9417d96f4efSBrian Somers 	}
9427d96f4efSBrian Somers 
9437d96f4efSBrian Somers /* Check that at least the server address has been defined */
944ccd57eeaSPaolo Pisati 	if (server_addr.s_addr == 0) {
945ccd57eeaSPaolo Pisati 		ret = -1;
946ccd57eeaSPaolo Pisati 		goto getout;
947ccd57eeaSPaolo Pisati 	}
9487d96f4efSBrian Somers 
9497d96f4efSBrian Somers /* Add to linked list */
9507d96f4efSBrian Somers 	proxy_entry = malloc(sizeof(struct proxy_entry));
951ccd57eeaSPaolo Pisati 	if (proxy_entry == NULL) {
952ccd57eeaSPaolo Pisati 		ret = -1;
953ccd57eeaSPaolo Pisati 		goto getout;
954ccd57eeaSPaolo Pisati 	}
9557d96f4efSBrian Somers 
9567d96f4efSBrian Somers 	proxy_entry->proxy_type = proxy_type;
9577d96f4efSBrian Somers 	proxy_entry->rule_index = rule_index;
9587d96f4efSBrian Somers 	proxy_entry->proto = proto;
9597d96f4efSBrian Somers 	proxy_entry->proxy_port = htons(proxy_port);
9607d96f4efSBrian Somers 	proxy_entry->server_port = htons(server_port);
9617d96f4efSBrian Somers 	proxy_entry->server_addr = server_addr;
9627d96f4efSBrian Somers 	proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
9637d96f4efSBrian Somers 	proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
9647d96f4efSBrian Somers 	proxy_entry->src_mask = src_mask;
9657d96f4efSBrian Somers 	proxy_entry->dst_mask = dst_mask;
9667d96f4efSBrian Somers 
9675e289f9eSPoul-Henning Kamp 	RuleAdd(la, proxy_entry);
9687d96f4efSBrian Somers 
969ccd57eeaSPaolo Pisati getout:
970ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
971ccd57eeaSPaolo Pisati 	return (ret);
9727d96f4efSBrian Somers }
973