xref: /freebsd/sys/netinet/libalias/alias_proxy.c (revision 1cfd924f4e7ca3dc742905aaf5d828a21ad88191)
1f987e1bdSBrian Somers /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3fe267a55SPedro F. Giffuni  *
4e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
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     Initial development: April, 1998 (cjm)
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>
79effc8e57SLutz Donnerhacke 
807d96f4efSBrian Somers #include "alias.h"		/* Public API functions for libalias */
8175bc2620SGleb Smirnoff #include "alias_local.h"	/* Functions used by alias*.c */
82c649a2e0SGleb Smirnoff #endif
837d96f4efSBrian Somers 
847d96f4efSBrian Somers /*
857d96f4efSBrian Somers     Data structures
867d96f4efSBrian Somers  */
877d96f4efSBrian Somers 
887d96f4efSBrian Somers /*
897d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
907d96f4efSBrian Somers  * used to store proxy rules.
917d96f4efSBrian Somers  */
92f0f93429SDag-Erling Smørgrav struct proxy_entry {
935e289f9eSPoul-Henning Kamp 	struct libalias *la;
947d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
957d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
967d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
977d96f4efSBrian Somers 	int		rule_index;
987d96f4efSBrian Somers 	int		proxy_type;
997d96f4efSBrian Somers 	u_char		proto;
1007d96f4efSBrian Somers 	u_short		proxy_port;
1017d96f4efSBrian Somers 	u_short		server_port;
1027d96f4efSBrian Somers 
1037d96f4efSBrian Somers 	struct in_addr	server_addr;
1047d96f4efSBrian Somers 
1057d96f4efSBrian Somers 	struct in_addr	src_addr;
1067d96f4efSBrian Somers 	struct in_addr	src_mask;
1077d96f4efSBrian Somers 
1087d96f4efSBrian Somers 	struct in_addr	dst_addr;
1097d96f4efSBrian Somers 	struct in_addr	dst_mask;
1107d96f4efSBrian Somers 
1117d96f4efSBrian Somers 	struct proxy_entry *next;
1127d96f4efSBrian Somers 	struct proxy_entry *last;
1137d96f4efSBrian Somers };
1147d96f4efSBrian Somers 
1157d96f4efSBrian Somers /*
1167d96f4efSBrian Somers     File scope variables
1177d96f4efSBrian Somers */
1187d96f4efSBrian Somers 
1197d96f4efSBrian Somers /* Local (static) functions:
1207d96f4efSBrian Somers 
1217d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1227d96f4efSBrian Somers 				masks from integer (1-32) specification.
1237d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1247d96f4efSBrian Somers 				to IP address
1257d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1267d96f4efSBrian Somers 				to port number
1277d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1287d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1297d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1307d96f4efSBrian Somers 				having a certain rule number.
1317d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1327d96f4efSBrian Somers 				of a TCP stream.
1337d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1347d96f4efSBrian Somers 				destination of a proxied IP packet
1357d96f4efSBrian Somers */
1367d96f4efSBrian Somers 
1377d96f4efSBrian Somers static int	IpMask(int, struct in_addr *);
1387d96f4efSBrian Somers static int	IpAddr(char *, struct in_addr *);
1397d96f4efSBrian Somers static int	IpPort(char *, int, int *);
1405e289f9eSPoul-Henning Kamp static void	RuleAdd(struct libalias *la, struct proxy_entry *);
1417d96f4efSBrian Somers static void	RuleDelete(struct proxy_entry *);
1425e289f9eSPoul-Henning Kamp static int	RuleNumberDelete(struct libalias *la, int);
1437d96f4efSBrian Somers static void	ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1447d96f4efSBrian Somers static void	ProxyEncodeIpHeader(struct ip *, int);
1457d96f4efSBrian Somers 
1467d96f4efSBrian Somers static int
1477d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1487d96f4efSBrian Somers {
1497d96f4efSBrian Somers 	int i;
1507d96f4efSBrian Somers 	u_int imask;
1517d96f4efSBrian Somers 
1527d96f4efSBrian Somers 	if (nbits < 0 || nbits > 32)
153ffcb611aSDag-Erling Smørgrav 		return (-1);
1547d96f4efSBrian Somers 
1557d96f4efSBrian Somers 	imask = 0;
1567d96f4efSBrian Somers 	for (i = 0; i < nbits; i++)
1577d96f4efSBrian Somers 		imask = (imask >> 1) + 0x80000000;
1587d96f4efSBrian Somers 	mask->s_addr = htonl(imask);
1597d96f4efSBrian Somers 
160ffcb611aSDag-Erling Smørgrav 	return (0);
1617d96f4efSBrian Somers }
1627d96f4efSBrian Somers 
1637d96f4efSBrian Somers static int
1647d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1657d96f4efSBrian Somers {
1667d96f4efSBrian Somers 	if (inet_aton(s, addr) == 0)
167ffcb611aSDag-Erling Smørgrav 		return (-1);
1687d96f4efSBrian Somers 	else
169ffcb611aSDag-Erling Smørgrav 		return (0);
1707d96f4efSBrian Somers }
1717d96f4efSBrian Somers 
1727d96f4efSBrian Somers static int
1737d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1747d96f4efSBrian Somers {
1757d96f4efSBrian Somers 	int n;
1767d96f4efSBrian Somers 
1777d96f4efSBrian Somers 	n = sscanf(s, "%d", port);
178e9d5db28SGleb Smirnoff 	if (n != 1)
179e9d5db28SGleb Smirnoff #ifndef _KERNEL	/* XXX: we accept only numeric ports in kernel */
180e9d5db28SGleb Smirnoff 	{
1817d96f4efSBrian Somers 		struct servent *se;
1827d96f4efSBrian Somers 
1837d96f4efSBrian Somers 		if (proto == IPPROTO_TCP)
1847d96f4efSBrian Somers 			se = getservbyname(s, "tcp");
1857d96f4efSBrian Somers 		else if (proto == IPPROTO_UDP)
1867d96f4efSBrian Somers 			se = getservbyname(s, "udp");
1877d96f4efSBrian Somers 		else
188ffcb611aSDag-Erling Smørgrav 			return (-1);
1897d96f4efSBrian Somers 
1907d96f4efSBrian Somers 		if (se == NULL)
191ffcb611aSDag-Erling Smørgrav 			return (-1);
1927d96f4efSBrian Somers 
1937d96f4efSBrian Somers 		*port = (u_int)ntohs(se->s_port);
1947d96f4efSBrian Somers 	}
195e9d5db28SGleb Smirnoff #else
196e9d5db28SGleb Smirnoff 		return (-1);
197e9d5db28SGleb Smirnoff #endif
198ffcb611aSDag-Erling Smørgrav 	return (0);
1997d96f4efSBrian Somers }
2007d96f4efSBrian Somers 
2017d96f4efSBrian Somers void
2025e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
2037d96f4efSBrian Somers {
2047d96f4efSBrian Somers 	int rule_index;
2057d96f4efSBrian Somers 	struct proxy_entry *ptr;
2067d96f4efSBrian Somers 	struct proxy_entry *ptr_last;
2077d96f4efSBrian Somers 
208ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
209ccd57eeaSPaolo Pisati 
21098373126SEd Maste 	entry->la = la;
211f0f93429SDag-Erling Smørgrav 	if (la->proxyList == NULL) {
2125e289f9eSPoul-Henning Kamp 		la->proxyList = entry;
2137d96f4efSBrian Somers 		entry->last = NULL;
2147d96f4efSBrian Somers 		entry->next = NULL;
2157d96f4efSBrian Somers 		return;
2167d96f4efSBrian Somers 	}
2177d96f4efSBrian Somers 
2187d96f4efSBrian Somers 	rule_index = entry->rule_index;
2195e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
2207d96f4efSBrian Somers 	ptr_last = NULL;
221f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
222f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index >= rule_index) {
223f0f93429SDag-Erling Smørgrav 			if (ptr_last == NULL) {
2245e289f9eSPoul-Henning Kamp 				entry->next = la->proxyList;
2257d96f4efSBrian Somers 				entry->last = NULL;
2265e289f9eSPoul-Henning Kamp 				la->proxyList->last = entry;
2275e289f9eSPoul-Henning Kamp 				la->proxyList = entry;
2287d96f4efSBrian Somers 				return;
2297d96f4efSBrian Somers 			}
2307d96f4efSBrian Somers 			ptr_last->next = entry;
2317d96f4efSBrian Somers 			ptr->last = entry;
2327d96f4efSBrian Somers 			entry->last = ptr->last;
2337d96f4efSBrian Somers 			entry->next = ptr;
2347d96f4efSBrian Somers 			return;
2357d96f4efSBrian Somers 		}
2367d96f4efSBrian Somers 		ptr_last = ptr;
2377d96f4efSBrian Somers 		ptr = ptr->next;
2387d96f4efSBrian Somers 	}
2397d96f4efSBrian Somers 
2407d96f4efSBrian Somers 	ptr_last->next = entry;
2417d96f4efSBrian Somers 	entry->last = ptr_last;
2427d96f4efSBrian Somers 	entry->next = NULL;
2437d96f4efSBrian Somers }
2447d96f4efSBrian Somers 
2457d96f4efSBrian Somers static void
2467d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2477d96f4efSBrian Somers {
2485e289f9eSPoul-Henning Kamp 	struct libalias *la;
2495e289f9eSPoul-Henning Kamp 
2505e289f9eSPoul-Henning Kamp 	la = entry->la;
251ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2527d96f4efSBrian Somers 	if (entry->last != NULL)
2537d96f4efSBrian Somers 		entry->last->next = entry->next;
2547d96f4efSBrian Somers 	else
2555e289f9eSPoul-Henning Kamp 		la->proxyList = entry->next;
2567d96f4efSBrian Somers 
2577d96f4efSBrian Somers 	if (entry->next != NULL)
2587d96f4efSBrian Somers 		entry->next->last = entry->last;
2597d96f4efSBrian Somers 
2607d96f4efSBrian Somers 	free(entry);
2617d96f4efSBrian Somers }
2627d96f4efSBrian Somers 
2637d96f4efSBrian Somers static int
2645e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
2657d96f4efSBrian Somers {
2667d96f4efSBrian Somers 	int err;
2677d96f4efSBrian Somers 	struct proxy_entry *ptr;
2687d96f4efSBrian Somers 
269ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2707d96f4efSBrian Somers 	err = -1;
2715e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
272f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
2737d96f4efSBrian Somers 		struct proxy_entry *ptr_next;
2747d96f4efSBrian Somers 
2757d96f4efSBrian Somers 		ptr_next = ptr->next;
276f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index == rule_index) {
2777d96f4efSBrian Somers 			err = 0;
2787d96f4efSBrian Somers 			RuleDelete(ptr);
2797d96f4efSBrian Somers 		}
2807d96f4efSBrian Somers 		ptr = ptr_next;
2817d96f4efSBrian Somers 	}
2827d96f4efSBrian Somers 
283ffcb611aSDag-Erling Smørgrav 	return (err);
2847d96f4efSBrian Somers }
2857d96f4efSBrian Somers 
2867d96f4efSBrian Somers static void
287ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk,
2887d96f4efSBrian Somers     struct ip *pip,
2897d96f4efSBrian Somers     int maxpacketsize)
2907d96f4efSBrian Somers {
2917d96f4efSBrian Somers 	int slen;
2927d96f4efSBrian Somers 	char buffer[40];
2937d96f4efSBrian Somers 	struct tcphdr *tc;
2948144690aSEric van Gyzen 	char addrbuf[INET_ADDRSTRLEN];
2957d96f4efSBrian Somers 
2967d96f4efSBrian Somers 	/* Compute pointer to tcp header */
2979fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
2987d96f4efSBrian Somers 
2997d96f4efSBrian Somers 	/* Don't modify if once already modified */
300ed01a582SDag-Erling Smørgrav 	if (GetAckModified(lnk))
3017d96f4efSBrian Somers 		return;
3027d96f4efSBrian Somers 
3037d96f4efSBrian Somers 	/* Translate destination address and port to string form */
3047d96f4efSBrian Somers 	snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
3058144690aSEric van Gyzen 	    inet_ntoa_r(GetProxyAddress(lnk), INET_NTOA_BUF(addrbuf)),
3068144690aSEric van Gyzen 	    (u_int)ntohs(GetProxyPort(lnk)));
3077d96f4efSBrian Somers 
3087d96f4efSBrian Somers 	/* Pad string out to a multiple of two in length */
3097d96f4efSBrian Somers 	slen = strlen(buffer);
310f0f93429SDag-Erling Smørgrav 	switch (slen % 2) {
3117d96f4efSBrian Somers 	case 0:
3127d96f4efSBrian Somers 		strcat(buffer, " \n");
3137d96f4efSBrian Somers 		slen += 2;
3147d96f4efSBrian Somers 		break;
3157d96f4efSBrian Somers 	case 1:
3167d96f4efSBrian Somers 		strcat(buffer, "\n");
3177d96f4efSBrian Somers 		slen += 1;
3187d96f4efSBrian Somers 	}
3197d96f4efSBrian Somers 
3207d96f4efSBrian Somers 	/* Check for packet overflow */
321ed01a582SDag-Erling Smørgrav 	if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
3227d96f4efSBrian Somers 		return;
3237d96f4efSBrian Somers 
3247d96f4efSBrian Somers 	/* Shift existing TCP data and insert destination string */
3257d96f4efSBrian Somers 	{
3267d96f4efSBrian Somers 		int dlen;
3277d96f4efSBrian Somers 		int hlen;
3289160afeeSAlexander Kabaev 		char *p;
3297d96f4efSBrian Somers 
3307d96f4efSBrian Somers 		hlen = (pip->ip_hl + tc->th_off) << 2;
3317d96f4efSBrian Somers 		dlen = ntohs(pip->ip_len) - hlen;
3327d96f4efSBrian Somers 
3337d96f4efSBrian Somers 		/* Modify first packet that has data in it */
3347d96f4efSBrian Somers 		if (dlen == 0)
3357d96f4efSBrian Somers 			return;
3367d96f4efSBrian Somers 
3377d96f4efSBrian Somers 		p = (char *)pip;
3387d96f4efSBrian Somers 		p += hlen;
3397d96f4efSBrian Somers 
340c8d3ca72SGleb Smirnoff 		bcopy(p, p + slen, dlen);
3417d96f4efSBrian Somers 		memcpy(p, buffer, slen);
3427d96f4efSBrian Somers 	}
3437d96f4efSBrian Somers 
344*1cfd924fSGordon Bergling 	/* Save information about modified sequence number */
3457d96f4efSBrian Somers 	{
3467d96f4efSBrian Somers 		int delta;
3477d96f4efSBrian Somers 
348ed01a582SDag-Erling Smørgrav 		SetAckModified(lnk);
3494741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
3504741f3a1SPaolo Pisati 		delta = GetDeltaSeqOut(tc->th_seq, lnk);
3514741f3a1SPaolo Pisati 		AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
3524741f3a1SPaolo Pisati 		    tc->th_off);
3537d96f4efSBrian Somers 	}
3547d96f4efSBrian Somers 
3557d96f4efSBrian Somers 	/* Update IP header packet length and checksum */
3567d96f4efSBrian Somers 	{
3577d96f4efSBrian Somers 		int accumulate;
3587d96f4efSBrian Somers 
3597d96f4efSBrian Somers 		accumulate = pip->ip_len;
3607d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3617d96f4efSBrian Somers 		accumulate -= pip->ip_len;
3627d96f4efSBrian Somers 
3637d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3647d96f4efSBrian Somers 	}
3657d96f4efSBrian Somers 
3667d96f4efSBrian Somers 	/* Update TCP checksum, Use TcpChecksum since so many things have
3677d96f4efSBrian Somers 	   already changed. */
3687d96f4efSBrian Somers 
3697d96f4efSBrian Somers 	tc->th_sum = 0;
37059dde15eSGleb Smirnoff #ifdef _KERNEL
37159dde15eSGleb Smirnoff 	tc->th_x2 = 1;
37259dde15eSGleb Smirnoff #else
3737d96f4efSBrian Somers 	tc->th_sum = TcpChecksum(pip);
37459dde15eSGleb Smirnoff #endif
3757d96f4efSBrian Somers }
3767d96f4efSBrian Somers 
3777d96f4efSBrian Somers static void
378effc8e57SLutz Donnerhacke ProxyEncodeIpHeader(struct ip *pip, int maxpacketsize)
3797d96f4efSBrian Somers {
3807d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3817d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3827d96f4efSBrian Somers #define OPTION_LEN_INT32  2
383bc596e56SAlex Richardson 	_Alignas(_Alignof(u_short)) u_char option[OPTION_LEN_BYTES];
3847d96f4efSBrian Somers 
3856293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
3867d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 1 = %x\n", (u_int)IpChecksum(pip));
3877d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 1 = %x\n", (u_int)TcpChecksum(pip));
3884c32f5d2SBrian Somers #endif
3897d96f4efSBrian Somers 
390ed01a582SDag-Erling Smørgrav 	(void)maxpacketsize;
391ed01a582SDag-Erling Smørgrav 
3927d96f4efSBrian Somers 	/* Check to see that there is room to add an IP option */
3937d96f4efSBrian Somers 	if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
3947d96f4efSBrian Somers 		return;
3957d96f4efSBrian Somers 
3967d96f4efSBrian Somers 	/* Build option and copy into packet */
3977d96f4efSBrian Somers 	{
3987d96f4efSBrian Somers 		u_char *ptr;
3997d96f4efSBrian Somers 		struct tcphdr *tc;
4007d96f4efSBrian Somers 
4017d96f4efSBrian Somers 		ptr = (u_char *) pip;
4027d96f4efSBrian Somers 		ptr += 20;
4037d96f4efSBrian Somers 		memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
4047d96f4efSBrian Somers 
4057d96f4efSBrian Somers 		option[0] = 0x64;	/* class: 3 (reserved), option 4 */
4067d96f4efSBrian Somers 		option[1] = OPTION_LEN_BYTES;
4077d96f4efSBrian Somers 
4087d96f4efSBrian Somers 		memcpy(&option[2], (u_char *)&pip->ip_dst, 4);
4097d96f4efSBrian Somers 
4109fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
4117d96f4efSBrian Somers 		memcpy(&option[6], (u_char *)&tc->th_sport, 2);
4127d96f4efSBrian Somers 
4137d96f4efSBrian Somers 		memcpy(ptr, option, 8);
4147d96f4efSBrian Somers 	}
4157d96f4efSBrian Somers 
4167d96f4efSBrian Somers 	/* Update checksum, header length and packet length */
4177d96f4efSBrian Somers 	{
4187d96f4efSBrian Somers 		int i;
4197d96f4efSBrian Somers 		int accumulate;
4207d96f4efSBrian Somers 		u_short *sptr;
4217d96f4efSBrian Somers 
4227d96f4efSBrian Somers 		sptr = (u_short *) option;
4237d96f4efSBrian Somers 		accumulate = 0;
4247d96f4efSBrian Somers 		for (i = 0; i < OPTION_LEN_INT16; i++)
4257d96f4efSBrian Somers 			accumulate -= *(sptr++);
4267d96f4efSBrian Somers 
4277d96f4efSBrian Somers 		sptr = (u_short *) pip;
4287d96f4efSBrian Somers 		accumulate += *sptr;
4297d96f4efSBrian Somers 		pip->ip_hl += OPTION_LEN_INT32;
4307d96f4efSBrian Somers 		accumulate -= *sptr;
4317d96f4efSBrian Somers 
4327d96f4efSBrian Somers 		accumulate += pip->ip_len;
4337d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
4347d96f4efSBrian Somers 		accumulate -= pip->ip_len;
4357d96f4efSBrian Somers 
4367d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4377d96f4efSBrian Somers 	}
4387d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4397d96f4efSBrian Somers #undef OPTION_LEN_INT16
4407d96f4efSBrian Somers #undef OPTION_LEN_INT32
4416293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
4427d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 2 = %x\n", (u_int)IpChecksum(pip));
4437d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 2 = %x\n", (u_int)TcpChecksum(pip));
4444c32f5d2SBrian Somers #endif
4457d96f4efSBrian Somers }
4467d96f4efSBrian Somers 
4477d96f4efSBrian Somers /* Functions by other packet alias source files
4487d96f4efSBrian Somers 
4497d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4507d96f4efSBrian Somers 			    be proxied.
4517d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4527d96f4efSBrian Somers 			    for a packet which is to be redirected to
4537d96f4efSBrian Somers 			    a proxy server.
4547d96f4efSBrian Somers */
4557d96f4efSBrian Somers 
4567d96f4efSBrian Somers int
4574741f3a1SPaolo Pisati ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
4584741f3a1SPaolo Pisati     u_short * proxy_server_port, struct in_addr src_addr,
4594741f3a1SPaolo Pisati     struct in_addr dst_addr, u_short dst_port, u_char ip_p)
4607d96f4efSBrian Somers {
4617d96f4efSBrian Somers 	struct proxy_entry *ptr;
4627d96f4efSBrian Somers 
463ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4647d96f4efSBrian Somers 
4655e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
466f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
4677d96f4efSBrian Somers 		u_short proxy_port;
4687d96f4efSBrian Somers 
4697d96f4efSBrian Somers 		proxy_port = ptr->proxy_port;
4707d96f4efSBrian Somers 		if ((dst_port == proxy_port || proxy_port == 0)
4714741f3a1SPaolo Pisati 		    && ip_p == ptr->proto
472f0f93429SDag-Erling Smørgrav 		    && src_addr.s_addr != ptr->server_addr.s_addr) {
4737d96f4efSBrian Somers 			struct in_addr src_addr_masked;
4747d96f4efSBrian Somers 			struct in_addr dst_addr_masked;
4757d96f4efSBrian Somers 
4767d96f4efSBrian Somers 			src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4777d96f4efSBrian Somers 			dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4787d96f4efSBrian Somers 
4797d96f4efSBrian Somers 			if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
480f0f93429SDag-Erling Smørgrav 			    && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
4817d96f4efSBrian Somers 				if ((*proxy_server_port = ptr->server_port) == 0)
4827d96f4efSBrian Somers 					*proxy_server_port = dst_port;
4837d96f4efSBrian Somers 				*proxy_server_addr = ptr->server_addr;
484ffcb611aSDag-Erling Smørgrav 				return (ptr->proxy_type);
4857d96f4efSBrian Somers 			}
4867d96f4efSBrian Somers 		}
4877d96f4efSBrian Somers 		ptr = ptr->next;
4887d96f4efSBrian Somers 	}
4897d96f4efSBrian Somers 
490ffcb611aSDag-Erling Smørgrav 	return (0);
4917d96f4efSBrian Somers }
4927d96f4efSBrian Somers 
4937d96f4efSBrian Somers void
494ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk,
4957d96f4efSBrian Somers     struct ip *pip,
4967d96f4efSBrian Somers     int maxpacketsize,
4977d96f4efSBrian Somers     int proxy_type)
4987d96f4efSBrian Somers {
499ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
500ed01a582SDag-Erling Smørgrav 	(void)la;
501ed01a582SDag-Erling Smørgrav 
502f0f93429SDag-Erling Smørgrav 	switch (proxy_type) {
5037d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_IPHDR:
5047d96f4efSBrian Somers 		ProxyEncodeIpHeader(pip, maxpacketsize);
5057d96f4efSBrian Somers 		break;
5067d96f4efSBrian Somers 
5077d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_TCPSTREAM:
508ed01a582SDag-Erling Smørgrav 		ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
5097d96f4efSBrian Somers 		break;
5107d96f4efSBrian Somers 	}
5117d96f4efSBrian Somers }
5127d96f4efSBrian Somers 
5137d96f4efSBrian Somers /*
5147d96f4efSBrian Somers     Public API functions
5157d96f4efSBrian Somers */
5167d96f4efSBrian Somers 
5177d96f4efSBrian Somers /*
5187d96f4efSBrian Somers  * This function takes command strings of the form:
5197d96f4efSBrian Somers  *
5207d96f4efSBrian Somers  *   server <addr>[:<port>]
5217d96f4efSBrian Somers  *   [port <port>]
5227d96f4efSBrian Somers  *   [rule n]
5237d96f4efSBrian Somers  *   [proto tcp|udp]
5247d96f4efSBrian Somers  *   [src <addr>[/n]]
5257d96f4efSBrian Somers  *   [dst <addr>[/n]]
5267d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5277d96f4efSBrian Somers  *
5287d96f4efSBrian Somers  *   delete <rule number>
5297d96f4efSBrian Somers  *
5307d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5317d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5327d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5337d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5347d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5357d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5367d96f4efSBrian Somers  * others.
5377d96f4efSBrian Somers  */
538effc8e57SLutz Donnerhacke int
539effc8e57SLutz Donnerhacke LibAliasProxyRule(struct libalias *la, const char *cmd)
540effc8e57SLutz Donnerhacke {
541ccd57eeaSPaolo Pisati 	int i, n, len, ret;
5427d96f4efSBrian Somers 	int cmd_len;
5437d96f4efSBrian Somers 	int token_count;
5447d96f4efSBrian Somers 	int state;
5457d96f4efSBrian Somers 	char *token;
5467d96f4efSBrian Somers 	char buffer[256];
5477d96f4efSBrian Somers 	char str_port[sizeof(buffer)];
5487d96f4efSBrian Somers 	char str_server_port[sizeof(buffer)];
549d9e630b5SAndrey A. Chernov 	char *res = buffer;
5507d96f4efSBrian Somers 
5517d96f4efSBrian Somers 	int rule_index;
5527d96f4efSBrian Somers 	int proto;
5537d96f4efSBrian Somers 	int proxy_type;
5547d96f4efSBrian Somers 	int proxy_port;
5557d96f4efSBrian Somers 	int server_port;
5567d96f4efSBrian Somers 	struct in_addr server_addr;
5577d96f4efSBrian Somers 	struct in_addr src_addr, src_mask;
5587d96f4efSBrian Somers 	struct in_addr dst_addr, dst_mask;
5597d96f4efSBrian Somers 	struct proxy_entry *proxy_entry;
5607d96f4efSBrian Somers 
561ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
562ccd57eeaSPaolo Pisati 	ret = 0;
563effc8e57SLutz Donnerhacke 
5647d96f4efSBrian Somers 	/* Copy command line into a buffer */
5654834b77dSBrian Somers 	cmd += strspn(cmd, " \t");
5667d96f4efSBrian Somers 	cmd_len = strlen(cmd);
567ccd57eeaSPaolo Pisati 	if (cmd_len > (int)(sizeof(buffer) - 1)) {
568ccd57eeaSPaolo Pisati 		ret = -1;
569ccd57eeaSPaolo Pisati 		goto getout;
570ccd57eeaSPaolo Pisati 	}
5717d96f4efSBrian Somers 	strcpy(buffer, cmd);
5727d96f4efSBrian Somers 
5737d96f4efSBrian Somers 	/* Convert to lower case */
5747d96f4efSBrian Somers 	len = strlen(buffer);
5757d96f4efSBrian Somers 	for (i = 0; i < len; i++)
576d9e630b5SAndrey A. Chernov 		buffer[i] = tolower((unsigned char)buffer[i]);
5777d96f4efSBrian Somers 
5787d96f4efSBrian Somers 	/* Set default proxy type */
5797d96f4efSBrian Somers 
5807d96f4efSBrian Somers 	/* Set up default values */
5817d96f4efSBrian Somers 	rule_index = 0;
5827d96f4efSBrian Somers 	proxy_type = PROXY_TYPE_ENCODE_NONE;
5837d96f4efSBrian Somers 	proto = IPPROTO_TCP;
5847d96f4efSBrian Somers 	proxy_port = 0;
5857d96f4efSBrian Somers 	server_addr.s_addr = 0;
5867d96f4efSBrian Somers 	server_port = 0;
5877d96f4efSBrian Somers 	src_addr.s_addr = 0;
5887d96f4efSBrian Somers 	IpMask(0, &src_mask);
5897d96f4efSBrian Somers 	dst_addr.s_addr = 0;
5907d96f4efSBrian Somers 	IpMask(0, &dst_mask);
5917d96f4efSBrian Somers 
5927d96f4efSBrian Somers 	str_port[0] = 0;
5937d96f4efSBrian Somers 	str_server_port[0] = 0;
5947d96f4efSBrian Somers 
5957d96f4efSBrian Somers 	/* Parse command string with state machine */
5967d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
5977d96f4efSBrian Somers #define STATE_READ_TYPE       1
5987d96f4efSBrian Somers #define STATE_READ_PORT       2
5997d96f4efSBrian Somers #define STATE_READ_SERVER     3
6007d96f4efSBrian Somers #define STATE_READ_RULE       4
6017d96f4efSBrian Somers #define STATE_READ_DELETE     5
6027d96f4efSBrian Somers #define STATE_READ_PROTO      6
6037d96f4efSBrian Somers #define STATE_READ_SRC        7
6047d96f4efSBrian Somers #define STATE_READ_DST        8
6057d96f4efSBrian Somers 	state = STATE_READ_KEYWORD;
606d9e630b5SAndrey A. Chernov 	token = strsep(&res, " \t");
6077d96f4efSBrian Somers 	token_count = 0;
608f0f93429SDag-Erling Smørgrav 	while (token != NULL) {
6097d96f4efSBrian Somers 		token_count++;
610f0f93429SDag-Erling Smørgrav 		switch (state) {
6117d96f4efSBrian Somers 		case STATE_READ_KEYWORD:
6127d96f4efSBrian Somers 			if (strcmp(token, "type") == 0)
6137d96f4efSBrian Somers 				state = STATE_READ_TYPE;
6147d96f4efSBrian Somers 			else if (strcmp(token, "port") == 0)
6157d96f4efSBrian Somers 				state = STATE_READ_PORT;
6167d96f4efSBrian Somers 			else if (strcmp(token, "server") == 0)
6177d96f4efSBrian Somers 				state = STATE_READ_SERVER;
6187d96f4efSBrian Somers 			else if (strcmp(token, "rule") == 0)
6197d96f4efSBrian Somers 				state = STATE_READ_RULE;
6207d96f4efSBrian Somers 			else if (strcmp(token, "delete") == 0)
6217d96f4efSBrian Somers 				state = STATE_READ_DELETE;
6227d96f4efSBrian Somers 			else if (strcmp(token, "proto") == 0)
6237d96f4efSBrian Somers 				state = STATE_READ_PROTO;
6247d96f4efSBrian Somers 			else if (strcmp(token, "src") == 0)
6257d96f4efSBrian Somers 				state = STATE_READ_SRC;
6267d96f4efSBrian Somers 			else if (strcmp(token, "dst") == 0)
6277d96f4efSBrian Somers 				state = STATE_READ_DST;
628ccd57eeaSPaolo Pisati 			else {
629ccd57eeaSPaolo Pisati 				ret = -1;
630ccd57eeaSPaolo Pisati 				goto getout;
631ccd57eeaSPaolo Pisati 			}
6327d96f4efSBrian Somers 			break;
6337d96f4efSBrian Somers 
6347d96f4efSBrian Somers 		case STATE_READ_TYPE:
6357d96f4efSBrian Somers 			if (strcmp(token, "encode_ip_hdr") == 0)
6367d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6377d96f4efSBrian Somers 			else if (strcmp(token, "encode_tcp_stream") == 0)
6387d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6397d96f4efSBrian Somers 			else if (strcmp(token, "no_encode") == 0)
6407d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_NONE;
641ccd57eeaSPaolo Pisati 			else {
642ccd57eeaSPaolo Pisati 				ret = -1;
643ccd57eeaSPaolo Pisati 				goto getout;
644ccd57eeaSPaolo Pisati 			}
6457d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6467d96f4efSBrian Somers 			break;
6477d96f4efSBrian Somers 
6487d96f4efSBrian Somers 		case STATE_READ_PORT:
6497d96f4efSBrian Somers 			strcpy(str_port, token);
6507d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6517d96f4efSBrian Somers 			break;
6527d96f4efSBrian Somers 
653effc8e57SLutz Donnerhacke 		case STATE_READ_SERVER: {
6547d96f4efSBrian Somers 			int err;
6557d96f4efSBrian Somers 			char *p;
6567d96f4efSBrian Somers 			char s[sizeof(buffer)];
6577d96f4efSBrian Somers 
6587d96f4efSBrian Somers 			p = token;
6597d96f4efSBrian Somers 			while (*p != ':' && *p != 0)
6607d96f4efSBrian Somers 				p++;
6617d96f4efSBrian Somers 
662f0f93429SDag-Erling Smørgrav 			if (*p != ':') {
6637d96f4efSBrian Somers 				err = IpAddr(token, &server_addr);
664ccd57eeaSPaolo Pisati 				if (err) {
665ccd57eeaSPaolo Pisati 					ret = -1;
666ccd57eeaSPaolo Pisati 					goto getout;
667ccd57eeaSPaolo Pisati 				}
668f0f93429SDag-Erling Smørgrav 			} else {
6697d96f4efSBrian Somers 				*p = ' ';
6707d96f4efSBrian Somers 
6717d96f4efSBrian Somers 				n = sscanf(token, "%s %s", s, str_server_port);
672ccd57eeaSPaolo Pisati 				if (n != 2) {
673ccd57eeaSPaolo Pisati 					ret = -1;
674ccd57eeaSPaolo Pisati 					goto getout;
675ccd57eeaSPaolo Pisati 				}
6767d96f4efSBrian Somers 
6777d96f4efSBrian Somers 				err = IpAddr(s, &server_addr);
678ccd57eeaSPaolo Pisati 				if (err) {
679ccd57eeaSPaolo Pisati 					ret = -1;
680ccd57eeaSPaolo Pisati 					goto getout;
681ccd57eeaSPaolo Pisati 				}
6827d96f4efSBrian Somers 			}
683effc8e57SLutz Donnerhacke 
6847d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6857d96f4efSBrian Somers 			break;
686effc8e57SLutz Donnerhacke 		}
6877d96f4efSBrian Somers 		case STATE_READ_RULE:
6887d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_index);
689ccd57eeaSPaolo Pisati 			if (n != 1 || rule_index < 0) {
690ccd57eeaSPaolo Pisati 				ret = -1;
691ccd57eeaSPaolo Pisati 				goto getout;
692ccd57eeaSPaolo Pisati 			}
6937d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6947d96f4efSBrian Somers 			break;
6957d96f4efSBrian Somers 
696effc8e57SLutz Donnerhacke 		case STATE_READ_DELETE:	{
6977d96f4efSBrian Somers 			int err;
6987d96f4efSBrian Somers 			int rule_to_delete;
6997d96f4efSBrian Somers 
700ccd57eeaSPaolo Pisati 			if (token_count != 2) {
701ccd57eeaSPaolo Pisati 				ret = -1;
702ccd57eeaSPaolo Pisati 				goto getout;
703ccd57eeaSPaolo Pisati 			}
7047d96f4efSBrian Somers 
7057d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_to_delete);
706ccd57eeaSPaolo Pisati 			if (n != 1) {
707ccd57eeaSPaolo Pisati 				ret = -1;
708ccd57eeaSPaolo Pisati 				goto getout;
709ccd57eeaSPaolo Pisati 			}
7105e289f9eSPoul-Henning Kamp 			err = RuleNumberDelete(la, rule_to_delete);
7117d96f4efSBrian Somers 			if (err)
712ccd57eeaSPaolo Pisati 				ret = -1;
713fdb727f4SConrad Meyer 			else
714ccd57eeaSPaolo Pisati 				ret = 0;
715ccd57eeaSPaolo Pisati 			goto getout;
7167d96f4efSBrian Somers 		}
7177d96f4efSBrian Somers 
7187d96f4efSBrian Somers 		case STATE_READ_PROTO:
7197d96f4efSBrian Somers 			if (strcmp(token, "tcp") == 0)
7207d96f4efSBrian Somers 				proto = IPPROTO_TCP;
7217d96f4efSBrian Somers 			else if (strcmp(token, "udp") == 0)
7227d96f4efSBrian Somers 				proto = IPPROTO_UDP;
723ccd57eeaSPaolo Pisati 			else {
724ccd57eeaSPaolo Pisati 				ret = -1;
725ccd57eeaSPaolo Pisati 				goto getout;
726ccd57eeaSPaolo Pisati 			}
7277d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7287d96f4efSBrian Somers 			break;
7297d96f4efSBrian Somers 
7307d96f4efSBrian Somers 		case STATE_READ_SRC:
731effc8e57SLutz Donnerhacke 		case STATE_READ_DST: {
7327d96f4efSBrian Somers 			int err;
7337d96f4efSBrian Somers 			char *p;
7347d96f4efSBrian Somers 			struct in_addr mask;
7357d96f4efSBrian Somers 			struct in_addr addr;
7367d96f4efSBrian Somers 
7377d96f4efSBrian Somers 			p = token;
7387d96f4efSBrian Somers 			while (*p != '/' && *p != 0)
7397d96f4efSBrian Somers 				p++;
7407d96f4efSBrian Somers 
741f0f93429SDag-Erling Smørgrav 			if (*p != '/') {
7427d96f4efSBrian Somers 				IpMask(32, &mask);
7437d96f4efSBrian Somers 				err = IpAddr(token, &addr);
744ccd57eeaSPaolo Pisati 				if (err) {
745ccd57eeaSPaolo Pisati 					ret = -1;
746ccd57eeaSPaolo Pisati 					goto getout;
747ccd57eeaSPaolo Pisati 				}
748f0f93429SDag-Erling Smørgrav 			} else {
7497d96f4efSBrian Somers 				int nbits;
7507d96f4efSBrian Somers 				char s[sizeof(buffer)];
7517d96f4efSBrian Somers 
7527d96f4efSBrian Somers 				*p = ' ';
7537d96f4efSBrian Somers 				n = sscanf(token, "%s %d", s, &nbits);
754ccd57eeaSPaolo Pisati 				if (n != 2) {
755ccd57eeaSPaolo Pisati 					ret = -1;
756ccd57eeaSPaolo Pisati 					goto getout;
757ccd57eeaSPaolo Pisati 				}
7587d96f4efSBrian Somers 
7597d96f4efSBrian Somers 				err = IpAddr(s, &addr);
760ccd57eeaSPaolo Pisati 				if (err) {
761ccd57eeaSPaolo Pisati 					ret = -1;
762ccd57eeaSPaolo Pisati 					goto getout;
763ccd57eeaSPaolo Pisati 				}
7647d96f4efSBrian Somers 
7657d96f4efSBrian Somers 				err = IpMask(nbits, &mask);
766ccd57eeaSPaolo Pisati 				if (err) {
767ccd57eeaSPaolo Pisati 					ret = -1;
768ccd57eeaSPaolo Pisati 					goto getout;
769ccd57eeaSPaolo Pisati 				}
7707d96f4efSBrian Somers 			}
7717d96f4efSBrian Somers 
772f0f93429SDag-Erling Smørgrav 			if (state == STATE_READ_SRC) {
7737d96f4efSBrian Somers 				src_addr = addr;
7747d96f4efSBrian Somers 				src_mask = mask;
775f0f93429SDag-Erling Smørgrav 			} else {
7767d96f4efSBrian Somers 				dst_addr = addr;
7777d96f4efSBrian Somers 				dst_mask = mask;
7787d96f4efSBrian Somers 			}
779effc8e57SLutz Donnerhacke 
7807d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7817d96f4efSBrian Somers 			break;
782effc8e57SLutz Donnerhacke 		}
7837d96f4efSBrian Somers 
7847d96f4efSBrian Somers 		default:
785ccd57eeaSPaolo Pisati 			ret = -1;
786ccd57eeaSPaolo Pisati 			goto getout;
7877d96f4efSBrian Somers 			break;
7887d96f4efSBrian Somers 		}
7897d96f4efSBrian Somers 
790d9e630b5SAndrey A. Chernov 		do {
791d9e630b5SAndrey A. Chernov 			token = strsep(&res, " \t");
792d9e630b5SAndrey A. Chernov 		} while (token != NULL && !*token);
7937d96f4efSBrian Somers 	}
7947d96f4efSBrian Somers #undef STATE_READ_KEYWORD
7957d96f4efSBrian Somers #undef STATE_READ_TYPE
7967d96f4efSBrian Somers #undef STATE_READ_PORT
7977d96f4efSBrian Somers #undef STATE_READ_SERVER
7987d96f4efSBrian Somers #undef STATE_READ_RULE
7997d96f4efSBrian Somers #undef STATE_READ_DELETE
8007d96f4efSBrian Somers #undef STATE_READ_PROTO
8017d96f4efSBrian Somers #undef STATE_READ_SRC
8027d96f4efSBrian Somers #undef STATE_READ_DST
8037d96f4efSBrian Somers 
804effc8e57SLutz Donnerhacke 	/* Convert port strings to numbers.
805effc8e57SLutz Donnerhacke 	   This needs to be done after the string is parsed, because
806effc8e57SLutz Donnerhacke 	   the prototype might not be designated before the ports
807effc8e57SLutz Donnerhacke 	   (which might be symbolic entries in /etc/services) */
8087d96f4efSBrian Somers 
809f0f93429SDag-Erling Smørgrav 	if (strlen(str_port) != 0) {
8107d96f4efSBrian Somers 		int err;
8117d96f4efSBrian Somers 
8127d96f4efSBrian Somers 		err = IpPort(str_port, proto, &proxy_port);
813ccd57eeaSPaolo Pisati 		if (err) {
814ccd57eeaSPaolo Pisati 			ret = -1;
815ccd57eeaSPaolo Pisati 			goto getout;
816ccd57eeaSPaolo Pisati 		}
817f0f93429SDag-Erling Smørgrav 	} else {
8187d96f4efSBrian Somers 		proxy_port = 0;
8197d96f4efSBrian Somers 	}
8207d96f4efSBrian Somers 
821f0f93429SDag-Erling Smørgrav 	if (strlen(str_server_port) != 0) {
8227d96f4efSBrian Somers 		int err;
8237d96f4efSBrian Somers 
8247d96f4efSBrian Somers 		err = IpPort(str_server_port, proto, &server_port);
825ccd57eeaSPaolo Pisati 		if (err) {
826ccd57eeaSPaolo Pisati 			ret = -1;
827ccd57eeaSPaolo Pisati 			goto getout;
828ccd57eeaSPaolo Pisati 		}
829f0f93429SDag-Erling Smørgrav 	} else {
8307d96f4efSBrian Somers 		server_port = 0;
8317d96f4efSBrian Somers 	}
8327d96f4efSBrian Somers 
8337d96f4efSBrian Somers 	/* Check that at least the server address has been defined */
834ccd57eeaSPaolo Pisati 	if (server_addr.s_addr == 0) {
835ccd57eeaSPaolo Pisati 		ret = -1;
836ccd57eeaSPaolo Pisati 		goto getout;
837ccd57eeaSPaolo Pisati 	}
8387d96f4efSBrian Somers 
8397d96f4efSBrian Somers 	/* Add to linked list */
8407d96f4efSBrian Somers 	proxy_entry = malloc(sizeof(struct proxy_entry));
841ccd57eeaSPaolo Pisati 	if (proxy_entry == NULL) {
842ccd57eeaSPaolo Pisati 		ret = -1;
843ccd57eeaSPaolo Pisati 		goto getout;
844ccd57eeaSPaolo Pisati 	}
8457d96f4efSBrian Somers 
8467d96f4efSBrian Somers 	proxy_entry->proxy_type = proxy_type;
8477d96f4efSBrian Somers 	proxy_entry->rule_index = rule_index;
8487d96f4efSBrian Somers 	proxy_entry->proto = proto;
8497d96f4efSBrian Somers 	proxy_entry->proxy_port = htons(proxy_port);
8507d96f4efSBrian Somers 	proxy_entry->server_port = htons(server_port);
8517d96f4efSBrian Somers 	proxy_entry->server_addr = server_addr;
8527d96f4efSBrian Somers 	proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
8537d96f4efSBrian Somers 	proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
8547d96f4efSBrian Somers 	proxy_entry->src_mask = src_mask;
8557d96f4efSBrian Somers 	proxy_entry->dst_mask = dst_mask;
8567d96f4efSBrian Somers 
8575e289f9eSPoul-Henning Kamp 	RuleAdd(la, proxy_entry);
8587d96f4efSBrian Somers 
859ccd57eeaSPaolo Pisati getout:
860ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
861ccd57eeaSPaolo Pisati 	return (ret);
8627d96f4efSBrian Somers }
863