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