1f987e1bdSBrian Somers /*-
2*fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*fe267a55SPedro F. Giffuni  *
4e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <[email protected]>
5f987e1bdSBrian Somers  * All rights reserved.
6f987e1bdSBrian Somers  *
7f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers  * are met:
10f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers  *
16f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers  * SUCH DAMAGE.
27f987e1bdSBrian Somers  */
28f987e1bdSBrian Somers 
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
30e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$");
31e2505aa6SMatthew Dillon 
327d96f4efSBrian Somers /* file: alias_proxy.c
337d96f4efSBrian Somers 
347d96f4efSBrian Somers     This file encapsulates special operations related to transparent
357d96f4efSBrian Somers     proxy redirection.  This is where packets with a particular destination,
367d96f4efSBrian Somers     usually tcp port 80, are redirected to a proxy server.
377d96f4efSBrian Somers 
387d96f4efSBrian Somers     When packets are proxied, the destination address and port are
397d96f4efSBrian Somers     modified.  In certain cases, it is necessary to somehow encode
407d96f4efSBrian Somers     the original address/port info into the packet.  Two methods are
417d96f4efSBrian Somers     presently supported: addition of a [DEST addr port] string at the
429d5abbddSJens Schweikhardt     beginning of a tcp stream, or inclusion of an optional field
437d96f4efSBrian Somers     in the IP header.
447d96f4efSBrian Somers 
457d96f4efSBrian Somers     There is one public API function:
467d96f4efSBrian Somers 
477d96f4efSBrian Somers 	PacketAliasProxyRule()    -- Adds and deletes proxy
487d96f4efSBrian Somers 				     rules.
497d96f4efSBrian Somers 
507d96f4efSBrian Somers     Rules are stored in a linear linked list, so lookup efficiency
517d96f4efSBrian Somers     won't be too good for large lists.
527d96f4efSBrian Somers 
537d96f4efSBrian Somers 
547d96f4efSBrian Somers     Initial development: April, 1998 (cjm)
557d96f4efSBrian Somers */
567d96f4efSBrian Somers 
577d96f4efSBrian Somers 
587d96f4efSBrian Somers /* System includes */
59c649a2e0SGleb Smirnoff #ifdef _KERNEL
60c649a2e0SGleb Smirnoff #include <sys/param.h>
61c649a2e0SGleb Smirnoff #include <sys/ctype.h>
62c649a2e0SGleb Smirnoff #include <sys/libkern.h>
63c649a2e0SGleb Smirnoff #include <sys/limits.h>
64c649a2e0SGleb Smirnoff #else
65c649a2e0SGleb Smirnoff #include <sys/types.h>
667d96f4efSBrian Somers #include <ctype.h>
677d96f4efSBrian Somers #include <stdio.h>
687d96f4efSBrian Somers #include <stdlib.h>
697d96f4efSBrian Somers #include <netdb.h>
70be4f3cd0SPaolo Pisati #include <string.h>
71c649a2e0SGleb Smirnoff #endif
727d96f4efSBrian Somers 
737d96f4efSBrian Somers #include <netinet/tcp.h>
747d96f4efSBrian Somers 
75c649a2e0SGleb Smirnoff #ifdef _KERNEL
76c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
7775bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
78be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
79c649a2e0SGleb Smirnoff #else
80be4f3cd0SPaolo Pisati #include <arpa/inet.h>
817d96f4efSBrian Somers #include "alias.h"		/* Public API functions for libalias */
8275bc2620SGleb Smirnoff #include "alias_local.h"	/* Functions used by alias*.c */
83c649a2e0SGleb Smirnoff #endif
847d96f4efSBrian Somers 
857d96f4efSBrian Somers /*
867d96f4efSBrian Somers     Data structures
877d96f4efSBrian Somers  */
887d96f4efSBrian Somers 
897d96f4efSBrian Somers /*
907d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
917d96f4efSBrian Somers  * used to store proxy rules.
927d96f4efSBrian Somers  */
93f0f93429SDag-Erling Smørgrav struct proxy_entry {
945e289f9eSPoul-Henning Kamp 	struct libalias *la;
957d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
967d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
977d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
987d96f4efSBrian Somers 	int		rule_index;
997d96f4efSBrian Somers 	int		proxy_type;
1007d96f4efSBrian Somers 	u_char		proto;
1017d96f4efSBrian Somers 	u_short		proxy_port;
1027d96f4efSBrian Somers 	u_short		server_port;
1037d96f4efSBrian Somers 
1047d96f4efSBrian Somers 	struct in_addr	server_addr;
1057d96f4efSBrian Somers 
1067d96f4efSBrian Somers 	struct in_addr	src_addr;
1077d96f4efSBrian Somers 	struct in_addr	src_mask;
1087d96f4efSBrian Somers 
1097d96f4efSBrian Somers 	struct in_addr	dst_addr;
1107d96f4efSBrian Somers 	struct in_addr	dst_mask;
1117d96f4efSBrian Somers 
1127d96f4efSBrian Somers 	struct proxy_entry *next;
1137d96f4efSBrian Somers 	struct proxy_entry *last;
1147d96f4efSBrian Somers };
1157d96f4efSBrian Somers 
1167d96f4efSBrian Somers 
1177d96f4efSBrian Somers 
1187d96f4efSBrian Somers /*
1197d96f4efSBrian Somers     File scope variables
1207d96f4efSBrian Somers */
1217d96f4efSBrian Somers 
1227d96f4efSBrian Somers 
1237d96f4efSBrian Somers 
1247d96f4efSBrian Somers /* Local (static) functions:
1257d96f4efSBrian Somers 
1267d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1277d96f4efSBrian Somers 				masks from integer (1-32) specification.
1287d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1297d96f4efSBrian Somers 				to IP address
1307d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1317d96f4efSBrian Somers 				to port number
1327d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1337d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1347d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1357d96f4efSBrian Somers 				having a certain rule number.
1367d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1377d96f4efSBrian Somers 				of a TCP stream.
1387d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1397d96f4efSBrian Somers 				destination of a proxied IP packet
1407d96f4efSBrian Somers */
1417d96f4efSBrian Somers 
1427d96f4efSBrian Somers static int	IpMask(int, struct in_addr *);
1437d96f4efSBrian Somers static int	IpAddr(char *, struct in_addr *);
1447d96f4efSBrian Somers static int	IpPort(char *, int, int *);
1455e289f9eSPoul-Henning Kamp static void	RuleAdd(struct libalias *la, struct proxy_entry *);
1467d96f4efSBrian Somers static void	RuleDelete(struct proxy_entry *);
1475e289f9eSPoul-Henning Kamp static int	RuleNumberDelete(struct libalias *la, int);
1487d96f4efSBrian Somers static void	ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1497d96f4efSBrian Somers static void	ProxyEncodeIpHeader(struct ip *, int);
1507d96f4efSBrian Somers 
1517d96f4efSBrian Somers static int
1527d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1537d96f4efSBrian Somers {
1547d96f4efSBrian Somers 	int i;
1557d96f4efSBrian Somers 	u_int imask;
1567d96f4efSBrian Somers 
1577d96f4efSBrian Somers 	if (nbits < 0 || nbits > 32)
158ffcb611aSDag-Erling Smørgrav 		return (-1);
1597d96f4efSBrian Somers 
1607d96f4efSBrian Somers 	imask = 0;
1617d96f4efSBrian Somers 	for (i = 0; i < nbits; i++)
1627d96f4efSBrian Somers 		imask = (imask >> 1) + 0x80000000;
1637d96f4efSBrian Somers 	mask->s_addr = htonl(imask);
1647d96f4efSBrian Somers 
165ffcb611aSDag-Erling Smørgrav 	return (0);
1667d96f4efSBrian Somers }
1677d96f4efSBrian Somers 
1687d96f4efSBrian Somers static int
1697d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1707d96f4efSBrian Somers {
1717d96f4efSBrian Somers 	if (inet_aton(s, addr) == 0)
172ffcb611aSDag-Erling Smørgrav 		return (-1);
1737d96f4efSBrian Somers 	else
174ffcb611aSDag-Erling Smørgrav 		return (0);
1757d96f4efSBrian Somers }
1767d96f4efSBrian Somers 
1777d96f4efSBrian Somers static int
1787d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1797d96f4efSBrian Somers {
1807d96f4efSBrian Somers 	int n;
1817d96f4efSBrian Somers 
1827d96f4efSBrian Somers 	n = sscanf(s, "%d", port);
183e9d5db28SGleb Smirnoff 	if (n != 1)
184e9d5db28SGleb Smirnoff #ifndef _KERNEL	/* XXX: we accept only numeric ports in kernel */
185e9d5db28SGleb Smirnoff 	{
1867d96f4efSBrian Somers 		struct servent *se;
1877d96f4efSBrian Somers 
1887d96f4efSBrian Somers 		if (proto == IPPROTO_TCP)
1897d96f4efSBrian Somers 			se = getservbyname(s, "tcp");
1907d96f4efSBrian Somers 		else if (proto == IPPROTO_UDP)
1917d96f4efSBrian Somers 			se = getservbyname(s, "udp");
1927d96f4efSBrian Somers 		else
193ffcb611aSDag-Erling Smørgrav 			return (-1);
1947d96f4efSBrian Somers 
1957d96f4efSBrian Somers 		if (se == NULL)
196ffcb611aSDag-Erling Smørgrav 			return (-1);
1977d96f4efSBrian Somers 
1987d96f4efSBrian Somers 		*port = (u_int) ntohs(se->s_port);
1997d96f4efSBrian Somers 	}
200e9d5db28SGleb Smirnoff #else
201e9d5db28SGleb Smirnoff 		return (-1);
202e9d5db28SGleb Smirnoff #endif
203ffcb611aSDag-Erling Smørgrav 	return (0);
2047d96f4efSBrian Somers }
2057d96f4efSBrian Somers 
2067d96f4efSBrian Somers void
2075e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
2087d96f4efSBrian Somers {
2097d96f4efSBrian Somers 	int rule_index;
2107d96f4efSBrian Somers 	struct proxy_entry *ptr;
2117d96f4efSBrian Somers 	struct proxy_entry *ptr_last;
2127d96f4efSBrian Somers 
213ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
214ccd57eeaSPaolo Pisati 
21598373126SEd Maste 	entry->la = la;
216f0f93429SDag-Erling Smørgrav 	if (la->proxyList == NULL) {
2175e289f9eSPoul-Henning Kamp 		la->proxyList = entry;
2187d96f4efSBrian Somers 		entry->last = NULL;
2197d96f4efSBrian Somers 		entry->next = NULL;
2207d96f4efSBrian Somers 		return;
2217d96f4efSBrian Somers 	}
2227d96f4efSBrian Somers 
2237d96f4efSBrian Somers 	rule_index = entry->rule_index;
2245e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
2257d96f4efSBrian Somers 	ptr_last = NULL;
226f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
227f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index >= rule_index) {
228f0f93429SDag-Erling Smørgrav 			if (ptr_last == NULL) {
2295e289f9eSPoul-Henning Kamp 				entry->next = la->proxyList;
2307d96f4efSBrian Somers 				entry->last = NULL;
2315e289f9eSPoul-Henning Kamp 				la->proxyList->last = entry;
2325e289f9eSPoul-Henning Kamp 				la->proxyList = entry;
2337d96f4efSBrian Somers 				return;
2347d96f4efSBrian Somers 			}
2357d96f4efSBrian Somers 			ptr_last->next = entry;
2367d96f4efSBrian Somers 			ptr->last = entry;
2377d96f4efSBrian Somers 			entry->last = ptr->last;
2387d96f4efSBrian Somers 			entry->next = ptr;
2397d96f4efSBrian Somers 			return;
2407d96f4efSBrian Somers 		}
2417d96f4efSBrian Somers 		ptr_last = ptr;
2427d96f4efSBrian Somers 		ptr = ptr->next;
2437d96f4efSBrian Somers 	}
2447d96f4efSBrian Somers 
2457d96f4efSBrian Somers 	ptr_last->next = entry;
2467d96f4efSBrian Somers 	entry->last = ptr_last;
2477d96f4efSBrian Somers 	entry->next = NULL;
2487d96f4efSBrian Somers }
2497d96f4efSBrian Somers 
2507d96f4efSBrian Somers static void
2517d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2527d96f4efSBrian Somers {
2535e289f9eSPoul-Henning Kamp 	struct libalias *la;
2545e289f9eSPoul-Henning Kamp 
2555e289f9eSPoul-Henning Kamp 	la = entry->la;
256ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2577d96f4efSBrian Somers 	if (entry->last != NULL)
2587d96f4efSBrian Somers 		entry->last->next = entry->next;
2597d96f4efSBrian Somers 	else
2605e289f9eSPoul-Henning Kamp 		la->proxyList = entry->next;
2617d96f4efSBrian Somers 
2627d96f4efSBrian Somers 	if (entry->next != NULL)
2637d96f4efSBrian Somers 		entry->next->last = entry->last;
2647d96f4efSBrian Somers 
2657d96f4efSBrian Somers 	free(entry);
2667d96f4efSBrian Somers }
2677d96f4efSBrian Somers 
2687d96f4efSBrian Somers static int
2695e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
2707d96f4efSBrian Somers {
2717d96f4efSBrian Somers 	int err;
2727d96f4efSBrian Somers 	struct proxy_entry *ptr;
2737d96f4efSBrian Somers 
274ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2757d96f4efSBrian Somers 	err = -1;
2765e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
277f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
2787d96f4efSBrian Somers 		struct proxy_entry *ptr_next;
2797d96f4efSBrian Somers 
2807d96f4efSBrian Somers 		ptr_next = ptr->next;
281f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index == rule_index) {
2827d96f4efSBrian Somers 			err = 0;
2837d96f4efSBrian Somers 			RuleDelete(ptr);
2847d96f4efSBrian Somers 		}
2857d96f4efSBrian Somers 		ptr = ptr_next;
2867d96f4efSBrian Somers 	}
2877d96f4efSBrian Somers 
288ffcb611aSDag-Erling Smørgrav 	return (err);
2897d96f4efSBrian Somers }
2907d96f4efSBrian Somers 
2917d96f4efSBrian Somers static void
292ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk,
2937d96f4efSBrian Somers     struct ip *pip,
2947d96f4efSBrian Somers     int maxpacketsize)
2957d96f4efSBrian Somers {
2967d96f4efSBrian Somers 	int slen;
2977d96f4efSBrian Somers 	char buffer[40];
2987d96f4efSBrian Somers 	struct tcphdr *tc;
2998144690aSEric van Gyzen 	char addrbuf[INET_ADDRSTRLEN];
3007d96f4efSBrian Somers 
3017d96f4efSBrian Somers /* Compute pointer to tcp header */
3029fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
3037d96f4efSBrian Somers 
3047d96f4efSBrian Somers /* Don't modify if once already modified */
3057d96f4efSBrian Somers 
306ed01a582SDag-Erling Smørgrav 	if (GetAckModified(lnk))
3077d96f4efSBrian Somers 		return;
3087d96f4efSBrian Somers 
3097d96f4efSBrian Somers /* Translate destination address and port to string form */
3107d96f4efSBrian Somers 	snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
3118144690aSEric van Gyzen 	    inet_ntoa_r(GetProxyAddress(lnk), INET_NTOA_BUF(addrbuf)),
3128144690aSEric van Gyzen 	    (u_int) ntohs(GetProxyPort(lnk)));
3137d96f4efSBrian Somers 
3147d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
3157d96f4efSBrian Somers 	slen = strlen(buffer);
316f0f93429SDag-Erling Smørgrav 	switch (slen % 2) {
3177d96f4efSBrian Somers 	case 0:
3187d96f4efSBrian Somers 		strcat(buffer, " \n");
3197d96f4efSBrian Somers 		slen += 2;
3207d96f4efSBrian Somers 		break;
3217d96f4efSBrian Somers 	case 1:
3227d96f4efSBrian Somers 		strcat(buffer, "\n");
3237d96f4efSBrian Somers 		slen += 1;
3247d96f4efSBrian Somers 	}
3257d96f4efSBrian Somers 
3267d96f4efSBrian Somers /* Check for packet overflow */
327ed01a582SDag-Erling Smørgrav 	if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
3287d96f4efSBrian Somers 		return;
3297d96f4efSBrian Somers 
3307d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
3317d96f4efSBrian Somers 	{
3327d96f4efSBrian Somers 		int dlen;
3337d96f4efSBrian Somers 		int hlen;
3349160afeeSAlexander Kabaev 		char *p;
3357d96f4efSBrian Somers 
3367d96f4efSBrian Somers 		hlen = (pip->ip_hl + tc->th_off) << 2;
3377d96f4efSBrian Somers 		dlen = ntohs(pip->ip_len) - hlen;
3387d96f4efSBrian Somers 
3397d96f4efSBrian Somers /* Modify first packet that has data in it */
3407d96f4efSBrian Somers 
3417d96f4efSBrian Somers 		if (dlen == 0)
3427d96f4efSBrian Somers 			return;
3437d96f4efSBrian Somers 
3447d96f4efSBrian Somers 		p = (char *)pip;
3457d96f4efSBrian Somers 		p += hlen;
3467d96f4efSBrian Somers 
347c8d3ca72SGleb Smirnoff 		bcopy(p, p + slen, dlen);
3487d96f4efSBrian Somers 		memcpy(p, buffer, slen);
3497d96f4efSBrian Somers 	}
3507d96f4efSBrian Somers 
3517d96f4efSBrian Somers /* Save information about modfied sequence number */
3527d96f4efSBrian Somers 	{
3537d96f4efSBrian Somers 		int delta;
3547d96f4efSBrian Somers 
355ed01a582SDag-Erling Smørgrav 		SetAckModified(lnk);
3564741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
3574741f3a1SPaolo Pisati 		delta = GetDeltaSeqOut(tc->th_seq, lnk);
3584741f3a1SPaolo Pisati 		AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
3594741f3a1SPaolo Pisati 		    tc->th_off);
3607d96f4efSBrian Somers 	}
3617d96f4efSBrian Somers 
3627d96f4efSBrian Somers /* Update IP header packet length and checksum */
3637d96f4efSBrian Somers 	{
3647d96f4efSBrian Somers 		int accumulate;
3657d96f4efSBrian Somers 
3667d96f4efSBrian Somers 		accumulate = pip->ip_len;
3677d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3687d96f4efSBrian Somers 		accumulate -= pip->ip_len;
3697d96f4efSBrian Somers 
3707d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3717d96f4efSBrian Somers 	}
3727d96f4efSBrian Somers 
3737d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
3747d96f4efSBrian Somers    already changed. */
3757d96f4efSBrian Somers 
3767d96f4efSBrian Somers 	tc->th_sum = 0;
37759dde15eSGleb Smirnoff #ifdef _KERNEL
37859dde15eSGleb Smirnoff 	tc->th_x2 = 1;
37959dde15eSGleb Smirnoff #else
3807d96f4efSBrian Somers 	tc->th_sum = TcpChecksum(pip);
38159dde15eSGleb Smirnoff #endif
3827d96f4efSBrian Somers }
3837d96f4efSBrian Somers 
3847d96f4efSBrian Somers static void
3857d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
3867d96f4efSBrian Somers     int maxpacketsize)
3877d96f4efSBrian Somers {
3887d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3897d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3907d96f4efSBrian Somers #define OPTION_LEN_INT32  2
3917d96f4efSBrian Somers 	u_char option[OPTION_LEN_BYTES];
3927d96f4efSBrian Somers 
3936293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
3947d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
3957d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
3964c32f5d2SBrian Somers #endif
3977d96f4efSBrian Somers 
398ed01a582SDag-Erling Smørgrav 	(void)maxpacketsize;
399ed01a582SDag-Erling Smørgrav 
4007d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
4017d96f4efSBrian Somers 	if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
4027d96f4efSBrian Somers 		return;
4037d96f4efSBrian Somers 
4047d96f4efSBrian Somers /* Build option and copy into packet */
4057d96f4efSBrian Somers 	{
4067d96f4efSBrian Somers 		u_char *ptr;
4077d96f4efSBrian Somers 		struct tcphdr *tc;
4087d96f4efSBrian Somers 
4097d96f4efSBrian Somers 		ptr = (u_char *) pip;
4107d96f4efSBrian Somers 		ptr += 20;
4117d96f4efSBrian Somers 		memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
4127d96f4efSBrian Somers 
4137d96f4efSBrian Somers 		option[0] = 0x64;	/* class: 3 (reserved), option 4 */
4147d96f4efSBrian Somers 		option[1] = OPTION_LEN_BYTES;
4157d96f4efSBrian Somers 
4167d96f4efSBrian Somers 		memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
4177d96f4efSBrian Somers 
4189fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
4197d96f4efSBrian Somers 		memcpy(&option[6], (u_char *) & tc->th_sport, 2);
4207d96f4efSBrian Somers 
4217d96f4efSBrian Somers 		memcpy(ptr, option, 8);
4227d96f4efSBrian Somers 	}
4237d96f4efSBrian Somers 
4247d96f4efSBrian Somers /* Update checksum, header length and packet length */
4257d96f4efSBrian Somers 	{
4267d96f4efSBrian Somers 		int i;
4277d96f4efSBrian Somers 		int accumulate;
4287d96f4efSBrian Somers 		u_short *sptr;
4297d96f4efSBrian Somers 
4307d96f4efSBrian Somers 		sptr = (u_short *) option;
4317d96f4efSBrian Somers 		accumulate = 0;
4327d96f4efSBrian Somers 		for (i = 0; i < OPTION_LEN_INT16; i++)
4337d96f4efSBrian Somers 			accumulate -= *(sptr++);
4347d96f4efSBrian Somers 
4357d96f4efSBrian Somers 		sptr = (u_short *) pip;
4367d96f4efSBrian Somers 		accumulate += *sptr;
4377d96f4efSBrian Somers 		pip->ip_hl += OPTION_LEN_INT32;
4387d96f4efSBrian Somers 		accumulate -= *sptr;
4397d96f4efSBrian Somers 
4407d96f4efSBrian Somers 		accumulate += pip->ip_len;
4417d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
4427d96f4efSBrian Somers 		accumulate -= pip->ip_len;
4437d96f4efSBrian Somers 
4447d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4457d96f4efSBrian Somers 	}
4467d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4477d96f4efSBrian Somers #undef OPTION_LEN_INT16
4487d96f4efSBrian Somers #undef OPTION_LEN_INT32
4496293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
4507d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
4517d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
4524c32f5d2SBrian Somers #endif
4537d96f4efSBrian Somers }
4547d96f4efSBrian Somers 
4557d96f4efSBrian Somers 
4567d96f4efSBrian Somers /* Functions by other packet alias source files
4577d96f4efSBrian Somers 
4587d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4597d96f4efSBrian Somers 			    be proxied.
4607d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4617d96f4efSBrian Somers 			    for a packet which is to be redirected to
4627d96f4efSBrian Somers 			    a proxy server.
4637d96f4efSBrian Somers */
4647d96f4efSBrian Somers 
4657d96f4efSBrian Somers int
4664741f3a1SPaolo Pisati ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
4674741f3a1SPaolo Pisati     u_short * proxy_server_port, struct in_addr src_addr,
4684741f3a1SPaolo Pisati     struct in_addr dst_addr, u_short dst_port, u_char ip_p)
4697d96f4efSBrian Somers {
4707d96f4efSBrian Somers 	struct proxy_entry *ptr;
4717d96f4efSBrian Somers 
472ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4737d96f4efSBrian Somers 
4745e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
475f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
4767d96f4efSBrian Somers 		u_short proxy_port;
4777d96f4efSBrian Somers 
4787d96f4efSBrian Somers 		proxy_port = ptr->proxy_port;
4797d96f4efSBrian Somers 		if ((dst_port == proxy_port || proxy_port == 0)
4804741f3a1SPaolo Pisati 		    && ip_p == ptr->proto
481f0f93429SDag-Erling Smørgrav 		    && src_addr.s_addr != ptr->server_addr.s_addr) {
4827d96f4efSBrian Somers 			struct in_addr src_addr_masked;
4837d96f4efSBrian Somers 			struct in_addr dst_addr_masked;
4847d96f4efSBrian Somers 
4857d96f4efSBrian Somers 			src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4867d96f4efSBrian Somers 			dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4877d96f4efSBrian Somers 
4887d96f4efSBrian Somers 			if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
489f0f93429SDag-Erling Smørgrav 			    && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
4907d96f4efSBrian Somers 				if ((*proxy_server_port = ptr->server_port) == 0)
4917d96f4efSBrian Somers 					*proxy_server_port = dst_port;
4927d96f4efSBrian Somers 				*proxy_server_addr = ptr->server_addr;
493ffcb611aSDag-Erling Smørgrav 				return (ptr->proxy_type);
4947d96f4efSBrian Somers 			}
4957d96f4efSBrian Somers 		}
4967d96f4efSBrian Somers 		ptr = ptr->next;
4977d96f4efSBrian Somers 	}
4987d96f4efSBrian Somers 
499ffcb611aSDag-Erling Smørgrav 	return (0);
5007d96f4efSBrian Somers }
5017d96f4efSBrian Somers 
5027d96f4efSBrian Somers void
503ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk,
5047d96f4efSBrian Somers     struct ip *pip,
5057d96f4efSBrian Somers     int maxpacketsize,
5067d96f4efSBrian Somers     int proxy_type)
5077d96f4efSBrian Somers {
508ed01a582SDag-Erling Smørgrav 
509ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
510ed01a582SDag-Erling Smørgrav 	(void)la;
511ed01a582SDag-Erling Smørgrav 
512f0f93429SDag-Erling Smørgrav 	switch (proxy_type) {
5137d96f4efSBrian Somers 		case PROXY_TYPE_ENCODE_IPHDR:
5147d96f4efSBrian Somers 		ProxyEncodeIpHeader(pip, maxpacketsize);
5157d96f4efSBrian Somers 		break;
5167d96f4efSBrian Somers 
5177d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_TCPSTREAM:
518ed01a582SDag-Erling Smørgrav 		ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
5197d96f4efSBrian Somers 		break;
5207d96f4efSBrian Somers 	}
5217d96f4efSBrian Somers }
5227d96f4efSBrian Somers 
5237d96f4efSBrian Somers 
5247d96f4efSBrian Somers /*
5257d96f4efSBrian Somers     Public API functions
5267d96f4efSBrian Somers */
5277d96f4efSBrian Somers 
5287d96f4efSBrian Somers int
5295e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd)
5307d96f4efSBrian Somers {
5317d96f4efSBrian Somers /*
5327d96f4efSBrian Somers  * This function takes command strings of the form:
5337d96f4efSBrian Somers  *
5347d96f4efSBrian Somers  *   server <addr>[:<port>]
5357d96f4efSBrian Somers  *   [port <port>]
5367d96f4efSBrian Somers  *   [rule n]
5377d96f4efSBrian Somers  *   [proto tcp|udp]
5387d96f4efSBrian Somers  *   [src <addr>[/n]]
5397d96f4efSBrian Somers  *   [dst <addr>[/n]]
5407d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5417d96f4efSBrian Somers  *
5427d96f4efSBrian Somers  *   delete <rule number>
5437d96f4efSBrian Somers  *
5447d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5457d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5467d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5477d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5487d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5497d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5507d96f4efSBrian Somers  * others.
5517d96f4efSBrian Somers  */
552ccd57eeaSPaolo Pisati 	int i, n, len, ret;
5537d96f4efSBrian Somers 	int cmd_len;
5547d96f4efSBrian Somers 	int token_count;
5557d96f4efSBrian Somers 	int state;
5567d96f4efSBrian Somers 	char *token;
5577d96f4efSBrian Somers 	char buffer[256];
5587d96f4efSBrian Somers 	char str_port[sizeof(buffer)];
5597d96f4efSBrian Somers 	char str_server_port[sizeof(buffer)];
560d9e630b5SAndrey A. Chernov 	char *res = buffer;
5617d96f4efSBrian Somers 
5627d96f4efSBrian Somers 	int rule_index;
5637d96f4efSBrian Somers 	int proto;
5647d96f4efSBrian Somers 	int proxy_type;
5657d96f4efSBrian Somers 	int proxy_port;
5667d96f4efSBrian Somers 	int server_port;
5677d96f4efSBrian Somers 	struct in_addr server_addr;
5687d96f4efSBrian Somers 	struct in_addr src_addr, src_mask;
5697d96f4efSBrian Somers 	struct in_addr dst_addr, dst_mask;
5707d96f4efSBrian Somers 	struct proxy_entry *proxy_entry;
5717d96f4efSBrian Somers 
572ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
573ccd57eeaSPaolo Pisati 	ret = 0;
5747d96f4efSBrian Somers /* Copy command line into a buffer */
5754834b77dSBrian Somers 	cmd += strspn(cmd, " \t");
5767d96f4efSBrian Somers 	cmd_len = strlen(cmd);
577ccd57eeaSPaolo Pisati 	if (cmd_len > (int)(sizeof(buffer) - 1)) {
578ccd57eeaSPaolo Pisati 		ret = -1;
579ccd57eeaSPaolo Pisati 		goto getout;
580ccd57eeaSPaolo Pisati 	}
5817d96f4efSBrian Somers 	strcpy(buffer, cmd);
5827d96f4efSBrian Somers 
5837d96f4efSBrian Somers /* Convert to lower case */
5847d96f4efSBrian Somers 	len = strlen(buffer);
5857d96f4efSBrian Somers 	for (i = 0; i < len; i++)
586d9e630b5SAndrey A. Chernov 		buffer[i] = tolower((unsigned char)buffer[i]);
5877d96f4efSBrian Somers 
5887d96f4efSBrian Somers /* Set default proxy type */
5897d96f4efSBrian Somers 
5907d96f4efSBrian Somers /* Set up default values */
5917d96f4efSBrian Somers 	rule_index = 0;
5927d96f4efSBrian Somers 	proxy_type = PROXY_TYPE_ENCODE_NONE;
5937d96f4efSBrian Somers 	proto = IPPROTO_TCP;
5947d96f4efSBrian Somers 	proxy_port = 0;
5957d96f4efSBrian Somers 	server_addr.s_addr = 0;
5967d96f4efSBrian Somers 	server_port = 0;
5977d96f4efSBrian Somers 	src_addr.s_addr = 0;
5987d96f4efSBrian Somers 	IpMask(0, &src_mask);
5997d96f4efSBrian Somers 	dst_addr.s_addr = 0;
6007d96f4efSBrian Somers 	IpMask(0, &dst_mask);
6017d96f4efSBrian Somers 
6027d96f4efSBrian Somers 	str_port[0] = 0;
6037d96f4efSBrian Somers 	str_server_port[0] = 0;
6047d96f4efSBrian Somers 
6057d96f4efSBrian Somers /* Parse command string with state machine */
6067d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
6077d96f4efSBrian Somers #define STATE_READ_TYPE       1
6087d96f4efSBrian Somers #define STATE_READ_PORT       2
6097d96f4efSBrian Somers #define STATE_READ_SERVER     3
6107d96f4efSBrian Somers #define STATE_READ_RULE       4
6117d96f4efSBrian Somers #define STATE_READ_DELETE     5
6127d96f4efSBrian Somers #define STATE_READ_PROTO      6
6137d96f4efSBrian Somers #define STATE_READ_SRC        7
6147d96f4efSBrian Somers #define STATE_READ_DST        8
6157d96f4efSBrian Somers 	state = STATE_READ_KEYWORD;
616d9e630b5SAndrey A. Chernov 	token = strsep(&res, " \t");
6177d96f4efSBrian Somers 	token_count = 0;
618f0f93429SDag-Erling Smørgrav 	while (token != NULL) {
6197d96f4efSBrian Somers 		token_count++;
620f0f93429SDag-Erling Smørgrav 		switch (state) {
6217d96f4efSBrian Somers 		case STATE_READ_KEYWORD:
6227d96f4efSBrian Somers 			if (strcmp(token, "type") == 0)
6237d96f4efSBrian Somers 				state = STATE_READ_TYPE;
6247d96f4efSBrian Somers 			else if (strcmp(token, "port") == 0)
6257d96f4efSBrian Somers 				state = STATE_READ_PORT;
6267d96f4efSBrian Somers 			else if (strcmp(token, "server") == 0)
6277d96f4efSBrian Somers 				state = STATE_READ_SERVER;
6287d96f4efSBrian Somers 			else if (strcmp(token, "rule") == 0)
6297d96f4efSBrian Somers 				state = STATE_READ_RULE;
6307d96f4efSBrian Somers 			else if (strcmp(token, "delete") == 0)
6317d96f4efSBrian Somers 				state = STATE_READ_DELETE;
6327d96f4efSBrian Somers 			else if (strcmp(token, "proto") == 0)
6337d96f4efSBrian Somers 				state = STATE_READ_PROTO;
6347d96f4efSBrian Somers 			else if (strcmp(token, "src") == 0)
6357d96f4efSBrian Somers 				state = STATE_READ_SRC;
6367d96f4efSBrian Somers 			else if (strcmp(token, "dst") == 0)
6377d96f4efSBrian Somers 				state = STATE_READ_DST;
638ccd57eeaSPaolo Pisati 			else {
639ccd57eeaSPaolo Pisati 				ret = -1;
640ccd57eeaSPaolo Pisati 				goto getout;
641ccd57eeaSPaolo Pisati 			}
6427d96f4efSBrian Somers 			break;
6437d96f4efSBrian Somers 
6447d96f4efSBrian Somers 		case STATE_READ_TYPE:
6457d96f4efSBrian Somers 			if (strcmp(token, "encode_ip_hdr") == 0)
6467d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6477d96f4efSBrian Somers 			else if (strcmp(token, "encode_tcp_stream") == 0)
6487d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6497d96f4efSBrian Somers 			else if (strcmp(token, "no_encode") == 0)
6507d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_NONE;
651ccd57eeaSPaolo Pisati 			else {
652ccd57eeaSPaolo Pisati 				ret = -1;
653ccd57eeaSPaolo Pisati 				goto getout;
654ccd57eeaSPaolo Pisati 			}
6557d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6567d96f4efSBrian Somers 			break;
6577d96f4efSBrian Somers 
6587d96f4efSBrian Somers 		case STATE_READ_PORT:
6597d96f4efSBrian Somers 			strcpy(str_port, token);
6607d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6617d96f4efSBrian Somers 			break;
6627d96f4efSBrian Somers 
6637d96f4efSBrian Somers 		case STATE_READ_SERVER:
6647d96f4efSBrian Somers 			{
6657d96f4efSBrian Somers 				int err;
6667d96f4efSBrian Somers 				char *p;
6677d96f4efSBrian Somers 				char s[sizeof(buffer)];
6687d96f4efSBrian Somers 
6697d96f4efSBrian Somers 				p = token;
6707d96f4efSBrian Somers 				while (*p != ':' && *p != 0)
6717d96f4efSBrian Somers 					p++;
6727d96f4efSBrian Somers 
673f0f93429SDag-Erling Smørgrav 				if (*p != ':') {
6747d96f4efSBrian Somers 					err = IpAddr(token, &server_addr);
675ccd57eeaSPaolo Pisati 					if (err) {
676ccd57eeaSPaolo Pisati 						ret = -1;
677ccd57eeaSPaolo Pisati 						goto getout;
678ccd57eeaSPaolo Pisati 					}
679f0f93429SDag-Erling Smørgrav 				} else {
6807d96f4efSBrian Somers 					*p = ' ';
6817d96f4efSBrian Somers 
6827d96f4efSBrian Somers 					n = sscanf(token, "%s %s", s, str_server_port);
683ccd57eeaSPaolo Pisati 					if (n != 2) {
684ccd57eeaSPaolo Pisati 						ret = -1;
685ccd57eeaSPaolo Pisati 						goto getout;
686ccd57eeaSPaolo Pisati 					}
6877d96f4efSBrian Somers 
6887d96f4efSBrian Somers 					err = IpAddr(s, &server_addr);
689ccd57eeaSPaolo Pisati 					if (err) {
690ccd57eeaSPaolo Pisati 						ret = -1;
691ccd57eeaSPaolo Pisati 						goto getout;
692ccd57eeaSPaolo Pisati 					}
6937d96f4efSBrian Somers 				}
6947d96f4efSBrian Somers 			}
6957d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6967d96f4efSBrian Somers 			break;
6977d96f4efSBrian Somers 
6987d96f4efSBrian Somers 		case STATE_READ_RULE:
6997d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_index);
700ccd57eeaSPaolo Pisati 			if (n != 1 || rule_index < 0) {
701ccd57eeaSPaolo Pisati 				ret = -1;
702ccd57eeaSPaolo Pisati 				goto getout;
703ccd57eeaSPaolo Pisati 			}
7047d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7057d96f4efSBrian Somers 			break;
7067d96f4efSBrian Somers 
7077d96f4efSBrian Somers 		case STATE_READ_DELETE:
7087d96f4efSBrian Somers 			{
7097d96f4efSBrian Somers 				int err;
7107d96f4efSBrian Somers 				int rule_to_delete;
7117d96f4efSBrian Somers 
712ccd57eeaSPaolo Pisati 				if (token_count != 2) {
713ccd57eeaSPaolo Pisati 					ret = -1;
714ccd57eeaSPaolo Pisati 					goto getout;
715ccd57eeaSPaolo Pisati 				}
7167d96f4efSBrian Somers 
7177d96f4efSBrian Somers 				n = sscanf(token, "%d", &rule_to_delete);
718ccd57eeaSPaolo Pisati 				if (n != 1) {
719ccd57eeaSPaolo Pisati 					ret = -1;
720ccd57eeaSPaolo Pisati 					goto getout;
721ccd57eeaSPaolo Pisati 				}
7225e289f9eSPoul-Henning Kamp 				err = RuleNumberDelete(la, rule_to_delete);
7237d96f4efSBrian Somers 				if (err)
724ccd57eeaSPaolo Pisati 					ret = -1;
725fdb727f4SConrad Meyer 				else
726ccd57eeaSPaolo Pisati 					ret = 0;
727ccd57eeaSPaolo Pisati 				goto getout;
7287d96f4efSBrian Somers 			}
7297d96f4efSBrian Somers 
7307d96f4efSBrian Somers 		case STATE_READ_PROTO:
7317d96f4efSBrian Somers 			if (strcmp(token, "tcp") == 0)
7327d96f4efSBrian Somers 				proto = IPPROTO_TCP;
7337d96f4efSBrian Somers 			else if (strcmp(token, "udp") == 0)
7347d96f4efSBrian Somers 				proto = IPPROTO_UDP;
735ccd57eeaSPaolo Pisati 			else {
736ccd57eeaSPaolo Pisati 				ret = -1;
737ccd57eeaSPaolo Pisati 				goto getout;
738ccd57eeaSPaolo Pisati 			}
7397d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7407d96f4efSBrian Somers 			break;
7417d96f4efSBrian Somers 
7427d96f4efSBrian Somers 		case STATE_READ_SRC:
7437d96f4efSBrian Somers 		case STATE_READ_DST:
7447d96f4efSBrian Somers 			{
7457d96f4efSBrian Somers 				int err;
7467d96f4efSBrian Somers 				char *p;
7477d96f4efSBrian Somers 				struct in_addr mask;
7487d96f4efSBrian Somers 				struct in_addr addr;
7497d96f4efSBrian Somers 
7507d96f4efSBrian Somers 				p = token;
7517d96f4efSBrian Somers 				while (*p != '/' && *p != 0)
7527d96f4efSBrian Somers 					p++;
7537d96f4efSBrian Somers 
754f0f93429SDag-Erling Smørgrav 				if (*p != '/') {
7557d96f4efSBrian Somers 					IpMask(32, &mask);
7567d96f4efSBrian Somers 					err = IpAddr(token, &addr);
757ccd57eeaSPaolo Pisati 					if (err) {
758ccd57eeaSPaolo Pisati 						ret = -1;
759ccd57eeaSPaolo Pisati 						goto getout;
760ccd57eeaSPaolo Pisati 					}
761f0f93429SDag-Erling Smørgrav 				} else {
7627d96f4efSBrian Somers 					int nbits;
7637d96f4efSBrian Somers 					char s[sizeof(buffer)];
7647d96f4efSBrian Somers 
7657d96f4efSBrian Somers 					*p = ' ';
7667d96f4efSBrian Somers 					n = sscanf(token, "%s %d", s, &nbits);
767ccd57eeaSPaolo Pisati 					if (n != 2) {
768ccd57eeaSPaolo Pisati 						ret = -1;
769ccd57eeaSPaolo Pisati 						goto getout;
770ccd57eeaSPaolo Pisati 					}
7717d96f4efSBrian Somers 
7727d96f4efSBrian Somers 					err = IpAddr(s, &addr);
773ccd57eeaSPaolo Pisati 					if (err) {
774ccd57eeaSPaolo Pisati 						ret = -1;
775ccd57eeaSPaolo Pisati 						goto getout;
776ccd57eeaSPaolo Pisati 					}
7777d96f4efSBrian Somers 
7787d96f4efSBrian Somers 					err = IpMask(nbits, &mask);
779ccd57eeaSPaolo Pisati 					if (err) {
780ccd57eeaSPaolo Pisati 						ret = -1;
781ccd57eeaSPaolo Pisati 						goto getout;
782ccd57eeaSPaolo Pisati 					}
7837d96f4efSBrian Somers 				}
7847d96f4efSBrian Somers 
785f0f93429SDag-Erling Smørgrav 				if (state == STATE_READ_SRC) {
7867d96f4efSBrian Somers 					src_addr = addr;
7877d96f4efSBrian Somers 					src_mask = mask;
788f0f93429SDag-Erling Smørgrav 				} else {
7897d96f4efSBrian Somers 					dst_addr = addr;
7907d96f4efSBrian Somers 					dst_mask = mask;
7917d96f4efSBrian Somers 				}
7927d96f4efSBrian Somers 			}
7937d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7947d96f4efSBrian Somers 			break;
7957d96f4efSBrian Somers 
7967d96f4efSBrian Somers 		default:
797ccd57eeaSPaolo Pisati 			ret = -1;
798ccd57eeaSPaolo Pisati 			goto getout;
7997d96f4efSBrian Somers 			break;
8007d96f4efSBrian Somers 		}
8017d96f4efSBrian Somers 
802d9e630b5SAndrey A. Chernov 		do {
803d9e630b5SAndrey A. Chernov 			token = strsep(&res, " \t");
804d9e630b5SAndrey A. Chernov 		} while (token != NULL && !*token);
8057d96f4efSBrian Somers 	}
8067d96f4efSBrian Somers #undef STATE_READ_KEYWORD
8077d96f4efSBrian Somers #undef STATE_READ_TYPE
8087d96f4efSBrian Somers #undef STATE_READ_PORT
8097d96f4efSBrian Somers #undef STATE_READ_SERVER
8107d96f4efSBrian Somers #undef STATE_READ_RULE
8117d96f4efSBrian Somers #undef STATE_READ_DELETE
8127d96f4efSBrian Somers #undef STATE_READ_PROTO
8137d96f4efSBrian Somers #undef STATE_READ_SRC
8147d96f4efSBrian Somers #undef STATE_READ_DST
8157d96f4efSBrian Somers 
8167d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
8177d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
8187d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
8197d96f4efSBrian Somers 
820f0f93429SDag-Erling Smørgrav 	if (strlen(str_port) != 0) {
8217d96f4efSBrian Somers 		int err;
8227d96f4efSBrian Somers 
8237d96f4efSBrian Somers 		err = IpPort(str_port, proto, &proxy_port);
824ccd57eeaSPaolo Pisati 		if (err) {
825ccd57eeaSPaolo Pisati 			ret = -1;
826ccd57eeaSPaolo Pisati 			goto getout;
827ccd57eeaSPaolo Pisati 		}
828f0f93429SDag-Erling Smørgrav 	} else {
8297d96f4efSBrian Somers 		proxy_port = 0;
8307d96f4efSBrian Somers 	}
8317d96f4efSBrian Somers 
832f0f93429SDag-Erling Smørgrav 	if (strlen(str_server_port) != 0) {
8337d96f4efSBrian Somers 		int err;
8347d96f4efSBrian Somers 
8357d96f4efSBrian Somers 		err = IpPort(str_server_port, proto, &server_port);
836ccd57eeaSPaolo Pisati 		if (err) {
837ccd57eeaSPaolo Pisati 			ret = -1;
838ccd57eeaSPaolo Pisati 			goto getout;
839ccd57eeaSPaolo Pisati 		}
840f0f93429SDag-Erling Smørgrav 	} else {
8417d96f4efSBrian Somers 		server_port = 0;
8427d96f4efSBrian Somers 	}
8437d96f4efSBrian Somers 
8447d96f4efSBrian Somers /* Check that at least the server address has been defined */
845ccd57eeaSPaolo Pisati 	if (server_addr.s_addr == 0) {
846ccd57eeaSPaolo Pisati 		ret = -1;
847ccd57eeaSPaolo Pisati 		goto getout;
848ccd57eeaSPaolo Pisati 	}
8497d96f4efSBrian Somers 
8507d96f4efSBrian Somers /* Add to linked list */
8517d96f4efSBrian Somers 	proxy_entry = malloc(sizeof(struct proxy_entry));
852ccd57eeaSPaolo Pisati 	if (proxy_entry == NULL) {
853ccd57eeaSPaolo Pisati 		ret = -1;
854ccd57eeaSPaolo Pisati 		goto getout;
855ccd57eeaSPaolo Pisati 	}
8567d96f4efSBrian Somers 
8577d96f4efSBrian Somers 	proxy_entry->proxy_type = proxy_type;
8587d96f4efSBrian Somers 	proxy_entry->rule_index = rule_index;
8597d96f4efSBrian Somers 	proxy_entry->proto = proto;
8607d96f4efSBrian Somers 	proxy_entry->proxy_port = htons(proxy_port);
8617d96f4efSBrian Somers 	proxy_entry->server_port = htons(server_port);
8627d96f4efSBrian Somers 	proxy_entry->server_addr = server_addr;
8637d96f4efSBrian Somers 	proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
8647d96f4efSBrian Somers 	proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
8657d96f4efSBrian Somers 	proxy_entry->src_mask = src_mask;
8667d96f4efSBrian Somers 	proxy_entry->dst_mask = dst_mask;
8677d96f4efSBrian Somers 
8685e289f9eSPoul-Henning Kamp 	RuleAdd(la, proxy_entry);
8697d96f4efSBrian Somers 
870ccd57eeaSPaolo Pisati getout:
871ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
872ccd57eeaSPaolo Pisati 	return (ret);
8737d96f4efSBrian Somers }
874