xref: /freebsd/sys/netinet/libalias/alias_proxy.c (revision fdb727f4f29312ca5d80583d2f05e144da6ef40c)
1f987e1bdSBrian Somers /*-
2e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3f987e1bdSBrian Somers  * All rights reserved.
4f987e1bdSBrian Somers  *
5f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
6f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
7f987e1bdSBrian Somers  * are met:
8f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
9f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
10f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
13f987e1bdSBrian Somers  *
14f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f987e1bdSBrian Somers  * SUCH DAMAGE.
25f987e1bdSBrian Somers  */
26f987e1bdSBrian Somers 
27e2505aa6SMatthew Dillon #include <sys/cdefs.h>
28e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$");
29e2505aa6SMatthew Dillon 
307d96f4efSBrian Somers /* file: alias_proxy.c
317d96f4efSBrian Somers 
327d96f4efSBrian Somers     This file encapsulates special operations related to transparent
337d96f4efSBrian Somers     proxy redirection.  This is where packets with a particular destination,
347d96f4efSBrian Somers     usually tcp port 80, are redirected to a proxy server.
357d96f4efSBrian Somers 
367d96f4efSBrian Somers     When packets are proxied, the destination address and port are
377d96f4efSBrian Somers     modified.  In certain cases, it is necessary to somehow encode
387d96f4efSBrian Somers     the original address/port info into the packet.  Two methods are
397d96f4efSBrian Somers     presently supported: addition of a [DEST addr port] string at the
409d5abbddSJens Schweikhardt     beginning of a tcp stream, or inclusion of an optional field
417d96f4efSBrian Somers     in the IP header.
427d96f4efSBrian Somers 
437d96f4efSBrian Somers     There is one public API function:
447d96f4efSBrian Somers 
457d96f4efSBrian Somers 	PacketAliasProxyRule()    -- Adds and deletes proxy
467d96f4efSBrian Somers 				     rules.
477d96f4efSBrian Somers 
487d96f4efSBrian Somers     Rules are stored in a linear linked list, so lookup efficiency
497d96f4efSBrian Somers     won't be too good for large lists.
507d96f4efSBrian Somers 
517d96f4efSBrian Somers 
527d96f4efSBrian Somers     Initial development: April, 1998 (cjm)
537d96f4efSBrian Somers */
547d96f4efSBrian Somers 
557d96f4efSBrian Somers 
567d96f4efSBrian Somers /* System includes */
57c649a2e0SGleb Smirnoff #ifdef _KERNEL
58c649a2e0SGleb Smirnoff #include <sys/param.h>
59c649a2e0SGleb Smirnoff #include <sys/ctype.h>
60c649a2e0SGleb Smirnoff #include <sys/libkern.h>
61c649a2e0SGleb Smirnoff #include <sys/limits.h>
62c649a2e0SGleb Smirnoff #else
63c649a2e0SGleb Smirnoff #include <sys/types.h>
647d96f4efSBrian Somers #include <ctype.h>
657d96f4efSBrian Somers #include <stdio.h>
667d96f4efSBrian Somers #include <stdlib.h>
677d96f4efSBrian Somers #include <netdb.h>
68be4f3cd0SPaolo Pisati #include <string.h>
69c649a2e0SGleb Smirnoff #endif
707d96f4efSBrian Somers 
717d96f4efSBrian Somers #include <netinet/tcp.h>
727d96f4efSBrian Somers 
73c649a2e0SGleb Smirnoff #ifdef _KERNEL
74c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
7575bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
76be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
77c649a2e0SGleb Smirnoff #else
78be4f3cd0SPaolo Pisati #include <arpa/inet.h>
797d96f4efSBrian Somers #include "alias.h"		/* Public API functions for libalias */
8075bc2620SGleb Smirnoff #include "alias_local.h"	/* Functions used by alias*.c */
81c649a2e0SGleb Smirnoff #endif
827d96f4efSBrian Somers 
837d96f4efSBrian Somers /*
847d96f4efSBrian Somers     Data structures
857d96f4efSBrian Somers  */
867d96f4efSBrian Somers 
877d96f4efSBrian Somers /*
887d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
897d96f4efSBrian Somers  * used to store proxy rules.
907d96f4efSBrian Somers  */
91f0f93429SDag-Erling Smørgrav struct proxy_entry {
925e289f9eSPoul-Henning Kamp 	struct libalias *la;
937d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
947d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
957d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
967d96f4efSBrian Somers 	int		rule_index;
977d96f4efSBrian Somers 	int		proxy_type;
987d96f4efSBrian Somers 	u_char		proto;
997d96f4efSBrian Somers 	u_short		proxy_port;
1007d96f4efSBrian Somers 	u_short		server_port;
1017d96f4efSBrian Somers 
1027d96f4efSBrian Somers 	struct in_addr	server_addr;
1037d96f4efSBrian Somers 
1047d96f4efSBrian Somers 	struct in_addr	src_addr;
1057d96f4efSBrian Somers 	struct in_addr	src_mask;
1067d96f4efSBrian Somers 
1077d96f4efSBrian Somers 	struct in_addr	dst_addr;
1087d96f4efSBrian Somers 	struct in_addr	dst_mask;
1097d96f4efSBrian Somers 
1107d96f4efSBrian Somers 	struct proxy_entry *next;
1117d96f4efSBrian Somers 	struct proxy_entry *last;
1127d96f4efSBrian Somers };
1137d96f4efSBrian Somers 
1147d96f4efSBrian Somers 
1157d96f4efSBrian Somers 
1167d96f4efSBrian Somers /*
1177d96f4efSBrian Somers     File scope variables
1187d96f4efSBrian Somers */
1197d96f4efSBrian Somers 
1207d96f4efSBrian Somers 
1217d96f4efSBrian Somers 
1227d96f4efSBrian Somers /* Local (static) functions:
1237d96f4efSBrian Somers 
1247d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1257d96f4efSBrian Somers 				masks from integer (1-32) specification.
1267d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1277d96f4efSBrian Somers 				to IP address
1287d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1297d96f4efSBrian Somers 				to port number
1307d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1317d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1327d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1337d96f4efSBrian Somers 				having a certain rule number.
1347d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1357d96f4efSBrian Somers 				of a TCP stream.
1367d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1377d96f4efSBrian Somers 				destination of a proxied IP packet
1387d96f4efSBrian Somers */
1397d96f4efSBrian Somers 
1407d96f4efSBrian Somers static int	IpMask(int, struct in_addr *);
1417d96f4efSBrian Somers static int	IpAddr(char *, struct in_addr *);
1427d96f4efSBrian Somers static int	IpPort(char *, int, int *);
1435e289f9eSPoul-Henning Kamp static void	RuleAdd(struct libalias *la, struct proxy_entry *);
1447d96f4efSBrian Somers static void	RuleDelete(struct proxy_entry *);
1455e289f9eSPoul-Henning Kamp static int	RuleNumberDelete(struct libalias *la, int);
1467d96f4efSBrian Somers static void	ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1477d96f4efSBrian Somers static void	ProxyEncodeIpHeader(struct ip *, int);
1487d96f4efSBrian Somers 
1497d96f4efSBrian Somers static int
1507d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1517d96f4efSBrian Somers {
1527d96f4efSBrian Somers 	int i;
1537d96f4efSBrian Somers 	u_int imask;
1547d96f4efSBrian Somers 
1557d96f4efSBrian Somers 	if (nbits < 0 || nbits > 32)
156ffcb611aSDag-Erling Smørgrav 		return (-1);
1577d96f4efSBrian Somers 
1587d96f4efSBrian Somers 	imask = 0;
1597d96f4efSBrian Somers 	for (i = 0; i < nbits; i++)
1607d96f4efSBrian Somers 		imask = (imask >> 1) + 0x80000000;
1617d96f4efSBrian Somers 	mask->s_addr = htonl(imask);
1627d96f4efSBrian Somers 
163ffcb611aSDag-Erling Smørgrav 	return (0);
1647d96f4efSBrian Somers }
1657d96f4efSBrian Somers 
1667d96f4efSBrian Somers static int
1677d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1687d96f4efSBrian Somers {
1697d96f4efSBrian Somers 	if (inet_aton(s, addr) == 0)
170ffcb611aSDag-Erling Smørgrav 		return (-1);
1717d96f4efSBrian Somers 	else
172ffcb611aSDag-Erling Smørgrav 		return (0);
1737d96f4efSBrian Somers }
1747d96f4efSBrian Somers 
1757d96f4efSBrian Somers static int
1767d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1777d96f4efSBrian Somers {
1787d96f4efSBrian Somers 	int n;
1797d96f4efSBrian Somers 
1807d96f4efSBrian Somers 	n = sscanf(s, "%d", port);
181e9d5db28SGleb Smirnoff 	if (n != 1)
182e9d5db28SGleb Smirnoff #ifndef _KERNEL	/* XXX: we accept only numeric ports in kernel */
183e9d5db28SGleb Smirnoff 	{
1847d96f4efSBrian Somers 		struct servent *se;
1857d96f4efSBrian Somers 
1867d96f4efSBrian Somers 		if (proto == IPPROTO_TCP)
1877d96f4efSBrian Somers 			se = getservbyname(s, "tcp");
1887d96f4efSBrian Somers 		else if (proto == IPPROTO_UDP)
1897d96f4efSBrian Somers 			se = getservbyname(s, "udp");
1907d96f4efSBrian Somers 		else
191ffcb611aSDag-Erling Smørgrav 			return (-1);
1927d96f4efSBrian Somers 
1937d96f4efSBrian Somers 		if (se == NULL)
194ffcb611aSDag-Erling Smørgrav 			return (-1);
1957d96f4efSBrian Somers 
1967d96f4efSBrian Somers 		*port = (u_int) ntohs(se->s_port);
1977d96f4efSBrian Somers 	}
198e9d5db28SGleb Smirnoff #else
199e9d5db28SGleb Smirnoff 		return (-1);
200e9d5db28SGleb Smirnoff #endif
201ffcb611aSDag-Erling Smørgrav 	return (0);
2027d96f4efSBrian Somers }
2037d96f4efSBrian Somers 
2047d96f4efSBrian Somers void
2055e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
2067d96f4efSBrian Somers {
2077d96f4efSBrian Somers 	int rule_index;
2087d96f4efSBrian Somers 	struct proxy_entry *ptr;
2097d96f4efSBrian Somers 	struct proxy_entry *ptr_last;
2107d96f4efSBrian Somers 
211ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
212ccd57eeaSPaolo Pisati 
21398373126SEd Maste 	entry->la = la;
214f0f93429SDag-Erling Smørgrav 	if (la->proxyList == NULL) {
2155e289f9eSPoul-Henning Kamp 		la->proxyList = entry;
2167d96f4efSBrian Somers 		entry->last = NULL;
2177d96f4efSBrian Somers 		entry->next = NULL;
2187d96f4efSBrian Somers 		return;
2197d96f4efSBrian Somers 	}
2207d96f4efSBrian Somers 
2217d96f4efSBrian Somers 	rule_index = entry->rule_index;
2225e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
2237d96f4efSBrian Somers 	ptr_last = NULL;
224f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
225f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index >= rule_index) {
226f0f93429SDag-Erling Smørgrav 			if (ptr_last == NULL) {
2275e289f9eSPoul-Henning Kamp 				entry->next = la->proxyList;
2287d96f4efSBrian Somers 				entry->last = NULL;
2295e289f9eSPoul-Henning Kamp 				la->proxyList->last = entry;
2305e289f9eSPoul-Henning Kamp 				la->proxyList = entry;
2317d96f4efSBrian Somers 				return;
2327d96f4efSBrian Somers 			}
2337d96f4efSBrian Somers 			ptr_last->next = entry;
2347d96f4efSBrian Somers 			ptr->last = entry;
2357d96f4efSBrian Somers 			entry->last = ptr->last;
2367d96f4efSBrian Somers 			entry->next = ptr;
2377d96f4efSBrian Somers 			return;
2387d96f4efSBrian Somers 		}
2397d96f4efSBrian Somers 		ptr_last = ptr;
2407d96f4efSBrian Somers 		ptr = ptr->next;
2417d96f4efSBrian Somers 	}
2427d96f4efSBrian Somers 
2437d96f4efSBrian Somers 	ptr_last->next = entry;
2447d96f4efSBrian Somers 	entry->last = ptr_last;
2457d96f4efSBrian Somers 	entry->next = NULL;
2467d96f4efSBrian Somers }
2477d96f4efSBrian Somers 
2487d96f4efSBrian Somers static void
2497d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2507d96f4efSBrian Somers {
2515e289f9eSPoul-Henning Kamp 	struct libalias *la;
2525e289f9eSPoul-Henning Kamp 
2535e289f9eSPoul-Henning Kamp 	la = entry->la;
254ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2557d96f4efSBrian Somers 	if (entry->last != NULL)
2567d96f4efSBrian Somers 		entry->last->next = entry->next;
2577d96f4efSBrian Somers 	else
2585e289f9eSPoul-Henning Kamp 		la->proxyList = entry->next;
2597d96f4efSBrian Somers 
2607d96f4efSBrian Somers 	if (entry->next != NULL)
2617d96f4efSBrian Somers 		entry->next->last = entry->last;
2627d96f4efSBrian Somers 
2637d96f4efSBrian Somers 	free(entry);
2647d96f4efSBrian Somers }
2657d96f4efSBrian Somers 
2667d96f4efSBrian Somers static int
2675e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
2687d96f4efSBrian Somers {
2697d96f4efSBrian Somers 	int err;
2707d96f4efSBrian Somers 	struct proxy_entry *ptr;
2717d96f4efSBrian Somers 
272ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
2737d96f4efSBrian Somers 	err = -1;
2745e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
275f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
2767d96f4efSBrian Somers 		struct proxy_entry *ptr_next;
2777d96f4efSBrian Somers 
2787d96f4efSBrian Somers 		ptr_next = ptr->next;
279f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index == rule_index) {
2807d96f4efSBrian Somers 			err = 0;
2817d96f4efSBrian Somers 			RuleDelete(ptr);
2827d96f4efSBrian Somers 		}
2837d96f4efSBrian Somers 		ptr = ptr_next;
2847d96f4efSBrian Somers 	}
2857d96f4efSBrian Somers 
286ffcb611aSDag-Erling Smørgrav 	return (err);
2877d96f4efSBrian Somers }
2887d96f4efSBrian Somers 
2897d96f4efSBrian Somers static void
290ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk,
2917d96f4efSBrian Somers     struct ip *pip,
2927d96f4efSBrian Somers     int maxpacketsize)
2937d96f4efSBrian Somers {
2947d96f4efSBrian Somers 	int slen;
2957d96f4efSBrian Somers 	char buffer[40];
2967d96f4efSBrian Somers 	struct tcphdr *tc;
2978144690aSEric van Gyzen 	char addrbuf[INET_ADDRSTRLEN];
2987d96f4efSBrian Somers 
2997d96f4efSBrian Somers /* Compute pointer to tcp header */
3009fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
3017d96f4efSBrian Somers 
3027d96f4efSBrian Somers /* Don't modify if once already modified */
3037d96f4efSBrian Somers 
304ed01a582SDag-Erling Smørgrav 	if (GetAckModified(lnk))
3057d96f4efSBrian Somers 		return;
3067d96f4efSBrian Somers 
3077d96f4efSBrian Somers /* Translate destination address and port to string form */
3087d96f4efSBrian Somers 	snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
3098144690aSEric van Gyzen 	    inet_ntoa_r(GetProxyAddress(lnk), INET_NTOA_BUF(addrbuf)),
3108144690aSEric van Gyzen 	    (u_int) ntohs(GetProxyPort(lnk)));
3117d96f4efSBrian Somers 
3127d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
3137d96f4efSBrian Somers 	slen = strlen(buffer);
314f0f93429SDag-Erling Smørgrav 	switch (slen % 2) {
3157d96f4efSBrian Somers 	case 0:
3167d96f4efSBrian Somers 		strcat(buffer, " \n");
3177d96f4efSBrian Somers 		slen += 2;
3187d96f4efSBrian Somers 		break;
3197d96f4efSBrian Somers 	case 1:
3207d96f4efSBrian Somers 		strcat(buffer, "\n");
3217d96f4efSBrian Somers 		slen += 1;
3227d96f4efSBrian Somers 	}
3237d96f4efSBrian Somers 
3247d96f4efSBrian Somers /* Check for packet overflow */
325ed01a582SDag-Erling Smørgrav 	if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
3267d96f4efSBrian Somers 		return;
3277d96f4efSBrian Somers 
3287d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
3297d96f4efSBrian Somers 	{
3307d96f4efSBrian Somers 		int dlen;
3317d96f4efSBrian Somers 		int hlen;
3329160afeeSAlexander Kabaev 		char *p;
3337d96f4efSBrian Somers 
3347d96f4efSBrian Somers 		hlen = (pip->ip_hl + tc->th_off) << 2;
3357d96f4efSBrian Somers 		dlen = ntohs(pip->ip_len) - hlen;
3367d96f4efSBrian Somers 
3377d96f4efSBrian Somers /* Modify first packet that has data in it */
3387d96f4efSBrian Somers 
3397d96f4efSBrian Somers 		if (dlen == 0)
3407d96f4efSBrian Somers 			return;
3417d96f4efSBrian Somers 
3427d96f4efSBrian Somers 		p = (char *)pip;
3437d96f4efSBrian Somers 		p += hlen;
3447d96f4efSBrian Somers 
345c8d3ca72SGleb Smirnoff 		bcopy(p, p + slen, dlen);
3467d96f4efSBrian Somers 		memcpy(p, buffer, slen);
3477d96f4efSBrian Somers 	}
3487d96f4efSBrian Somers 
3497d96f4efSBrian Somers /* Save information about modfied sequence number */
3507d96f4efSBrian Somers 	{
3517d96f4efSBrian Somers 		int delta;
3527d96f4efSBrian Somers 
353ed01a582SDag-Erling Smørgrav 		SetAckModified(lnk);
3544741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
3554741f3a1SPaolo Pisati 		delta = GetDeltaSeqOut(tc->th_seq, lnk);
3564741f3a1SPaolo Pisati 		AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
3574741f3a1SPaolo Pisati 		    tc->th_off);
3587d96f4efSBrian Somers 	}
3597d96f4efSBrian Somers 
3607d96f4efSBrian Somers /* Update IP header packet length and checksum */
3617d96f4efSBrian Somers 	{
3627d96f4efSBrian Somers 		int accumulate;
3637d96f4efSBrian Somers 
3647d96f4efSBrian Somers 		accumulate = pip->ip_len;
3657d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3667d96f4efSBrian Somers 		accumulate -= pip->ip_len;
3677d96f4efSBrian Somers 
3687d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3697d96f4efSBrian Somers 	}
3707d96f4efSBrian Somers 
3717d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
3727d96f4efSBrian Somers    already changed. */
3737d96f4efSBrian Somers 
3747d96f4efSBrian Somers 	tc->th_sum = 0;
37559dde15eSGleb Smirnoff #ifdef _KERNEL
37659dde15eSGleb Smirnoff 	tc->th_x2 = 1;
37759dde15eSGleb Smirnoff #else
3787d96f4efSBrian Somers 	tc->th_sum = TcpChecksum(pip);
37959dde15eSGleb Smirnoff #endif
3807d96f4efSBrian Somers }
3817d96f4efSBrian Somers 
3827d96f4efSBrian Somers static void
3837d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
3847d96f4efSBrian Somers     int maxpacketsize)
3857d96f4efSBrian Somers {
3867d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3877d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3887d96f4efSBrian Somers #define OPTION_LEN_INT32  2
3897d96f4efSBrian Somers 	u_char option[OPTION_LEN_BYTES];
3907d96f4efSBrian Somers 
3916293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
3927d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
3937d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
3944c32f5d2SBrian Somers #endif
3957d96f4efSBrian Somers 
396ed01a582SDag-Erling Smørgrav 	(void)maxpacketsize;
397ed01a582SDag-Erling Smørgrav 
3987d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
3997d96f4efSBrian Somers 	if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
4007d96f4efSBrian Somers 		return;
4017d96f4efSBrian Somers 
4027d96f4efSBrian Somers /* Build option and copy into packet */
4037d96f4efSBrian Somers 	{
4047d96f4efSBrian Somers 		u_char *ptr;
4057d96f4efSBrian Somers 		struct tcphdr *tc;
4067d96f4efSBrian Somers 
4077d96f4efSBrian Somers 		ptr = (u_char *) pip;
4087d96f4efSBrian Somers 		ptr += 20;
4097d96f4efSBrian Somers 		memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
4107d96f4efSBrian Somers 
4117d96f4efSBrian Somers 		option[0] = 0x64;	/* class: 3 (reserved), option 4 */
4127d96f4efSBrian Somers 		option[1] = OPTION_LEN_BYTES;
4137d96f4efSBrian Somers 
4147d96f4efSBrian Somers 		memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
4157d96f4efSBrian Somers 
4169fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
4177d96f4efSBrian Somers 		memcpy(&option[6], (u_char *) & tc->th_sport, 2);
4187d96f4efSBrian Somers 
4197d96f4efSBrian Somers 		memcpy(ptr, option, 8);
4207d96f4efSBrian Somers 	}
4217d96f4efSBrian Somers 
4227d96f4efSBrian Somers /* Update checksum, header length and packet length */
4237d96f4efSBrian Somers 	{
4247d96f4efSBrian Somers 		int i;
4257d96f4efSBrian Somers 		int accumulate;
4267d96f4efSBrian Somers 		u_short *sptr;
4277d96f4efSBrian Somers 
4287d96f4efSBrian Somers 		sptr = (u_short *) option;
4297d96f4efSBrian Somers 		accumulate = 0;
4307d96f4efSBrian Somers 		for (i = 0; i < OPTION_LEN_INT16; i++)
4317d96f4efSBrian Somers 			accumulate -= *(sptr++);
4327d96f4efSBrian Somers 
4337d96f4efSBrian Somers 		sptr = (u_short *) pip;
4347d96f4efSBrian Somers 		accumulate += *sptr;
4357d96f4efSBrian Somers 		pip->ip_hl += OPTION_LEN_INT32;
4367d96f4efSBrian Somers 		accumulate -= *sptr;
4377d96f4efSBrian Somers 
4387d96f4efSBrian Somers 		accumulate += pip->ip_len;
4397d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
4407d96f4efSBrian Somers 		accumulate -= pip->ip_len;
4417d96f4efSBrian Somers 
4427d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4437d96f4efSBrian Somers 	}
4447d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4457d96f4efSBrian Somers #undef OPTION_LEN_INT16
4467d96f4efSBrian Somers #undef OPTION_LEN_INT32
4476293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG
4487d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
4497d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
4504c32f5d2SBrian Somers #endif
4517d96f4efSBrian Somers }
4527d96f4efSBrian Somers 
4537d96f4efSBrian Somers 
4547d96f4efSBrian Somers /* Functions by other packet alias source files
4557d96f4efSBrian Somers 
4567d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4577d96f4efSBrian Somers 			    be proxied.
4587d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4597d96f4efSBrian Somers 			    for a packet which is to be redirected to
4607d96f4efSBrian Somers 			    a proxy server.
4617d96f4efSBrian Somers */
4627d96f4efSBrian Somers 
4637d96f4efSBrian Somers int
4644741f3a1SPaolo Pisati ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
4654741f3a1SPaolo Pisati     u_short * proxy_server_port, struct in_addr src_addr,
4664741f3a1SPaolo Pisati     struct in_addr dst_addr, u_short dst_port, u_char ip_p)
4677d96f4efSBrian Somers {
4687d96f4efSBrian Somers 	struct proxy_entry *ptr;
4697d96f4efSBrian Somers 
470ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4717d96f4efSBrian Somers 
4725e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
473f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
4747d96f4efSBrian Somers 		u_short proxy_port;
4757d96f4efSBrian Somers 
4767d96f4efSBrian Somers 		proxy_port = ptr->proxy_port;
4777d96f4efSBrian Somers 		if ((dst_port == proxy_port || proxy_port == 0)
4784741f3a1SPaolo Pisati 		    && ip_p == ptr->proto
479f0f93429SDag-Erling Smørgrav 		    && src_addr.s_addr != ptr->server_addr.s_addr) {
4807d96f4efSBrian Somers 			struct in_addr src_addr_masked;
4817d96f4efSBrian Somers 			struct in_addr dst_addr_masked;
4827d96f4efSBrian Somers 
4837d96f4efSBrian Somers 			src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4847d96f4efSBrian Somers 			dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4857d96f4efSBrian Somers 
4867d96f4efSBrian Somers 			if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
487f0f93429SDag-Erling Smørgrav 			    && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
4887d96f4efSBrian Somers 				if ((*proxy_server_port = ptr->server_port) == 0)
4897d96f4efSBrian Somers 					*proxy_server_port = dst_port;
4907d96f4efSBrian Somers 				*proxy_server_addr = ptr->server_addr;
491ffcb611aSDag-Erling Smørgrav 				return (ptr->proxy_type);
4927d96f4efSBrian Somers 			}
4937d96f4efSBrian Somers 		}
4947d96f4efSBrian Somers 		ptr = ptr->next;
4957d96f4efSBrian Somers 	}
4967d96f4efSBrian Somers 
497ffcb611aSDag-Erling Smørgrav 	return (0);
4987d96f4efSBrian Somers }
4997d96f4efSBrian Somers 
5007d96f4efSBrian Somers void
501ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk,
5027d96f4efSBrian Somers     struct ip *pip,
5037d96f4efSBrian Somers     int maxpacketsize,
5047d96f4efSBrian Somers     int proxy_type)
5057d96f4efSBrian Somers {
506ed01a582SDag-Erling Smørgrav 
507ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
508ed01a582SDag-Erling Smørgrav 	(void)la;
509ed01a582SDag-Erling Smørgrav 
510f0f93429SDag-Erling Smørgrav 	switch (proxy_type) {
5117d96f4efSBrian Somers 		case PROXY_TYPE_ENCODE_IPHDR:
5127d96f4efSBrian Somers 		ProxyEncodeIpHeader(pip, maxpacketsize);
5137d96f4efSBrian Somers 		break;
5147d96f4efSBrian Somers 
5157d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_TCPSTREAM:
516ed01a582SDag-Erling Smørgrav 		ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
5177d96f4efSBrian Somers 		break;
5187d96f4efSBrian Somers 	}
5197d96f4efSBrian Somers }
5207d96f4efSBrian Somers 
5217d96f4efSBrian Somers 
5227d96f4efSBrian Somers /*
5237d96f4efSBrian Somers     Public API functions
5247d96f4efSBrian Somers */
5257d96f4efSBrian Somers 
5267d96f4efSBrian Somers int
5275e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd)
5287d96f4efSBrian Somers {
5297d96f4efSBrian Somers /*
5307d96f4efSBrian Somers  * This function takes command strings of the form:
5317d96f4efSBrian Somers  *
5327d96f4efSBrian Somers  *   server <addr>[:<port>]
5337d96f4efSBrian Somers  *   [port <port>]
5347d96f4efSBrian Somers  *   [rule n]
5357d96f4efSBrian Somers  *   [proto tcp|udp]
5367d96f4efSBrian Somers  *   [src <addr>[/n]]
5377d96f4efSBrian Somers  *   [dst <addr>[/n]]
5387d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5397d96f4efSBrian Somers  *
5407d96f4efSBrian Somers  *   delete <rule number>
5417d96f4efSBrian Somers  *
5427d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5437d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5447d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5457d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5467d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5477d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5487d96f4efSBrian Somers  * others.
5497d96f4efSBrian Somers  */
550ccd57eeaSPaolo Pisati 	int i, n, len, ret;
5517d96f4efSBrian Somers 	int cmd_len;
5527d96f4efSBrian Somers 	int token_count;
5537d96f4efSBrian Somers 	int state;
5547d96f4efSBrian Somers 	char *token;
5557d96f4efSBrian Somers 	char buffer[256];
5567d96f4efSBrian Somers 	char str_port[sizeof(buffer)];
5577d96f4efSBrian Somers 	char str_server_port[sizeof(buffer)];
558d9e630b5SAndrey A. Chernov 	char *res = buffer;
5597d96f4efSBrian Somers 
5607d96f4efSBrian Somers 	int rule_index;
5617d96f4efSBrian Somers 	int proto;
5627d96f4efSBrian Somers 	int proxy_type;
5637d96f4efSBrian Somers 	int proxy_port;
5647d96f4efSBrian Somers 	int server_port;
5657d96f4efSBrian Somers 	struct in_addr server_addr;
5667d96f4efSBrian Somers 	struct in_addr src_addr, src_mask;
5677d96f4efSBrian Somers 	struct in_addr dst_addr, dst_mask;
5687d96f4efSBrian Somers 	struct proxy_entry *proxy_entry;
5697d96f4efSBrian Somers 
570ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
571ccd57eeaSPaolo Pisati 	ret = 0;
5727d96f4efSBrian Somers /* Copy command line into a buffer */
5734834b77dSBrian Somers 	cmd += strspn(cmd, " \t");
5747d96f4efSBrian Somers 	cmd_len = strlen(cmd);
575ccd57eeaSPaolo Pisati 	if (cmd_len > (int)(sizeof(buffer) - 1)) {
576ccd57eeaSPaolo Pisati 		ret = -1;
577ccd57eeaSPaolo Pisati 		goto getout;
578ccd57eeaSPaolo Pisati 	}
5797d96f4efSBrian Somers 	strcpy(buffer, cmd);
5807d96f4efSBrian Somers 
5817d96f4efSBrian Somers /* Convert to lower case */
5827d96f4efSBrian Somers 	len = strlen(buffer);
5837d96f4efSBrian Somers 	for (i = 0; i < len; i++)
584d9e630b5SAndrey A. Chernov 		buffer[i] = tolower((unsigned char)buffer[i]);
5857d96f4efSBrian Somers 
5867d96f4efSBrian Somers /* Set default proxy type */
5877d96f4efSBrian Somers 
5887d96f4efSBrian Somers /* Set up default values */
5897d96f4efSBrian Somers 	rule_index = 0;
5907d96f4efSBrian Somers 	proxy_type = PROXY_TYPE_ENCODE_NONE;
5917d96f4efSBrian Somers 	proto = IPPROTO_TCP;
5927d96f4efSBrian Somers 	proxy_port = 0;
5937d96f4efSBrian Somers 	server_addr.s_addr = 0;
5947d96f4efSBrian Somers 	server_port = 0;
5957d96f4efSBrian Somers 	src_addr.s_addr = 0;
5967d96f4efSBrian Somers 	IpMask(0, &src_mask);
5977d96f4efSBrian Somers 	dst_addr.s_addr = 0;
5987d96f4efSBrian Somers 	IpMask(0, &dst_mask);
5997d96f4efSBrian Somers 
6007d96f4efSBrian Somers 	str_port[0] = 0;
6017d96f4efSBrian Somers 	str_server_port[0] = 0;
6027d96f4efSBrian Somers 
6037d96f4efSBrian Somers /* Parse command string with state machine */
6047d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
6057d96f4efSBrian Somers #define STATE_READ_TYPE       1
6067d96f4efSBrian Somers #define STATE_READ_PORT       2
6077d96f4efSBrian Somers #define STATE_READ_SERVER     3
6087d96f4efSBrian Somers #define STATE_READ_RULE       4
6097d96f4efSBrian Somers #define STATE_READ_DELETE     5
6107d96f4efSBrian Somers #define STATE_READ_PROTO      6
6117d96f4efSBrian Somers #define STATE_READ_SRC        7
6127d96f4efSBrian Somers #define STATE_READ_DST        8
6137d96f4efSBrian Somers 	state = STATE_READ_KEYWORD;
614d9e630b5SAndrey A. Chernov 	token = strsep(&res, " \t");
6157d96f4efSBrian Somers 	token_count = 0;
616f0f93429SDag-Erling Smørgrav 	while (token != NULL) {
6177d96f4efSBrian Somers 		token_count++;
618f0f93429SDag-Erling Smørgrav 		switch (state) {
6197d96f4efSBrian Somers 		case STATE_READ_KEYWORD:
6207d96f4efSBrian Somers 			if (strcmp(token, "type") == 0)
6217d96f4efSBrian Somers 				state = STATE_READ_TYPE;
6227d96f4efSBrian Somers 			else if (strcmp(token, "port") == 0)
6237d96f4efSBrian Somers 				state = STATE_READ_PORT;
6247d96f4efSBrian Somers 			else if (strcmp(token, "server") == 0)
6257d96f4efSBrian Somers 				state = STATE_READ_SERVER;
6267d96f4efSBrian Somers 			else if (strcmp(token, "rule") == 0)
6277d96f4efSBrian Somers 				state = STATE_READ_RULE;
6287d96f4efSBrian Somers 			else if (strcmp(token, "delete") == 0)
6297d96f4efSBrian Somers 				state = STATE_READ_DELETE;
6307d96f4efSBrian Somers 			else if (strcmp(token, "proto") == 0)
6317d96f4efSBrian Somers 				state = STATE_READ_PROTO;
6327d96f4efSBrian Somers 			else if (strcmp(token, "src") == 0)
6337d96f4efSBrian Somers 				state = STATE_READ_SRC;
6347d96f4efSBrian Somers 			else if (strcmp(token, "dst") == 0)
6357d96f4efSBrian Somers 				state = STATE_READ_DST;
636ccd57eeaSPaolo Pisati 			else {
637ccd57eeaSPaolo Pisati 				ret = -1;
638ccd57eeaSPaolo Pisati 				goto getout;
639ccd57eeaSPaolo Pisati 			}
6407d96f4efSBrian Somers 			break;
6417d96f4efSBrian Somers 
6427d96f4efSBrian Somers 		case STATE_READ_TYPE:
6437d96f4efSBrian Somers 			if (strcmp(token, "encode_ip_hdr") == 0)
6447d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6457d96f4efSBrian Somers 			else if (strcmp(token, "encode_tcp_stream") == 0)
6467d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6477d96f4efSBrian Somers 			else if (strcmp(token, "no_encode") == 0)
6487d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_NONE;
649ccd57eeaSPaolo Pisati 			else {
650ccd57eeaSPaolo Pisati 				ret = -1;
651ccd57eeaSPaolo Pisati 				goto getout;
652ccd57eeaSPaolo Pisati 			}
6537d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6547d96f4efSBrian Somers 			break;
6557d96f4efSBrian Somers 
6567d96f4efSBrian Somers 		case STATE_READ_PORT:
6577d96f4efSBrian Somers 			strcpy(str_port, token);
6587d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6597d96f4efSBrian Somers 			break;
6607d96f4efSBrian Somers 
6617d96f4efSBrian Somers 		case STATE_READ_SERVER:
6627d96f4efSBrian Somers 			{
6637d96f4efSBrian Somers 				int err;
6647d96f4efSBrian Somers 				char *p;
6657d96f4efSBrian Somers 				char s[sizeof(buffer)];
6667d96f4efSBrian Somers 
6677d96f4efSBrian Somers 				p = token;
6687d96f4efSBrian Somers 				while (*p != ':' && *p != 0)
6697d96f4efSBrian Somers 					p++;
6707d96f4efSBrian Somers 
671f0f93429SDag-Erling Smørgrav 				if (*p != ':') {
6727d96f4efSBrian Somers 					err = IpAddr(token, &server_addr);
673ccd57eeaSPaolo Pisati 					if (err) {
674ccd57eeaSPaolo Pisati 						ret = -1;
675ccd57eeaSPaolo Pisati 						goto getout;
676ccd57eeaSPaolo Pisati 					}
677f0f93429SDag-Erling Smørgrav 				} else {
6787d96f4efSBrian Somers 					*p = ' ';
6797d96f4efSBrian Somers 
6807d96f4efSBrian Somers 					n = sscanf(token, "%s %s", s, str_server_port);
681ccd57eeaSPaolo Pisati 					if (n != 2) {
682ccd57eeaSPaolo Pisati 						ret = -1;
683ccd57eeaSPaolo Pisati 						goto getout;
684ccd57eeaSPaolo Pisati 					}
6857d96f4efSBrian Somers 
6867d96f4efSBrian Somers 					err = IpAddr(s, &server_addr);
687ccd57eeaSPaolo Pisati 					if (err) {
688ccd57eeaSPaolo Pisati 						ret = -1;
689ccd57eeaSPaolo Pisati 						goto getout;
690ccd57eeaSPaolo Pisati 					}
6917d96f4efSBrian Somers 				}
6927d96f4efSBrian Somers 			}
6937d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6947d96f4efSBrian Somers 			break;
6957d96f4efSBrian Somers 
6967d96f4efSBrian Somers 		case STATE_READ_RULE:
6977d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_index);
698ccd57eeaSPaolo Pisati 			if (n != 1 || rule_index < 0) {
699ccd57eeaSPaolo Pisati 				ret = -1;
700ccd57eeaSPaolo Pisati 				goto getout;
701ccd57eeaSPaolo Pisati 			}
7027d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7037d96f4efSBrian Somers 			break;
7047d96f4efSBrian Somers 
7057d96f4efSBrian Somers 		case STATE_READ_DELETE:
7067d96f4efSBrian Somers 			{
7077d96f4efSBrian Somers 				int err;
7087d96f4efSBrian Somers 				int rule_to_delete;
7097d96f4efSBrian Somers 
710ccd57eeaSPaolo Pisati 				if (token_count != 2) {
711ccd57eeaSPaolo Pisati 					ret = -1;
712ccd57eeaSPaolo Pisati 					goto getout;
713ccd57eeaSPaolo Pisati 				}
7147d96f4efSBrian Somers 
7157d96f4efSBrian Somers 				n = sscanf(token, "%d", &rule_to_delete);
716ccd57eeaSPaolo Pisati 				if (n != 1) {
717ccd57eeaSPaolo Pisati 					ret = -1;
718ccd57eeaSPaolo Pisati 					goto getout;
719ccd57eeaSPaolo Pisati 				}
7205e289f9eSPoul-Henning Kamp 				err = RuleNumberDelete(la, rule_to_delete);
7217d96f4efSBrian Somers 				if (err)
722ccd57eeaSPaolo Pisati 					ret = -1;
723*fdb727f4SConrad Meyer 				else
724ccd57eeaSPaolo Pisati 					ret = 0;
725ccd57eeaSPaolo Pisati 				goto getout;
7267d96f4efSBrian Somers 			}
7277d96f4efSBrian Somers 
7287d96f4efSBrian Somers 		case STATE_READ_PROTO:
7297d96f4efSBrian Somers 			if (strcmp(token, "tcp") == 0)
7307d96f4efSBrian Somers 				proto = IPPROTO_TCP;
7317d96f4efSBrian Somers 			else if (strcmp(token, "udp") == 0)
7327d96f4efSBrian Somers 				proto = IPPROTO_UDP;
733ccd57eeaSPaolo Pisati 			else {
734ccd57eeaSPaolo Pisati 				ret = -1;
735ccd57eeaSPaolo Pisati 				goto getout;
736ccd57eeaSPaolo Pisati 			}
7377d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7387d96f4efSBrian Somers 			break;
7397d96f4efSBrian Somers 
7407d96f4efSBrian Somers 		case STATE_READ_SRC:
7417d96f4efSBrian Somers 		case STATE_READ_DST:
7427d96f4efSBrian Somers 			{
7437d96f4efSBrian Somers 				int err;
7447d96f4efSBrian Somers 				char *p;
7457d96f4efSBrian Somers 				struct in_addr mask;
7467d96f4efSBrian Somers 				struct in_addr addr;
7477d96f4efSBrian Somers 
7487d96f4efSBrian Somers 				p = token;
7497d96f4efSBrian Somers 				while (*p != '/' && *p != 0)
7507d96f4efSBrian Somers 					p++;
7517d96f4efSBrian Somers 
752f0f93429SDag-Erling Smørgrav 				if (*p != '/') {
7537d96f4efSBrian Somers 					IpMask(32, &mask);
7547d96f4efSBrian Somers 					err = IpAddr(token, &addr);
755ccd57eeaSPaolo Pisati 					if (err) {
756ccd57eeaSPaolo Pisati 						ret = -1;
757ccd57eeaSPaolo Pisati 						goto getout;
758ccd57eeaSPaolo Pisati 					}
759f0f93429SDag-Erling Smørgrav 				} else {
7607d96f4efSBrian Somers 					int nbits;
7617d96f4efSBrian Somers 					char s[sizeof(buffer)];
7627d96f4efSBrian Somers 
7637d96f4efSBrian Somers 					*p = ' ';
7647d96f4efSBrian Somers 					n = sscanf(token, "%s %d", s, &nbits);
765ccd57eeaSPaolo Pisati 					if (n != 2) {
766ccd57eeaSPaolo Pisati 						ret = -1;
767ccd57eeaSPaolo Pisati 						goto getout;
768ccd57eeaSPaolo Pisati 					}
7697d96f4efSBrian Somers 
7707d96f4efSBrian Somers 					err = IpAddr(s, &addr);
771ccd57eeaSPaolo Pisati 					if (err) {
772ccd57eeaSPaolo Pisati 						ret = -1;
773ccd57eeaSPaolo Pisati 						goto getout;
774ccd57eeaSPaolo Pisati 					}
7757d96f4efSBrian Somers 
7767d96f4efSBrian Somers 					err = IpMask(nbits, &mask);
777ccd57eeaSPaolo Pisati 					if (err) {
778ccd57eeaSPaolo Pisati 						ret = -1;
779ccd57eeaSPaolo Pisati 						goto getout;
780ccd57eeaSPaolo Pisati 					}
7817d96f4efSBrian Somers 				}
7827d96f4efSBrian Somers 
783f0f93429SDag-Erling Smørgrav 				if (state == STATE_READ_SRC) {
7847d96f4efSBrian Somers 					src_addr = addr;
7857d96f4efSBrian Somers 					src_mask = mask;
786f0f93429SDag-Erling Smørgrav 				} else {
7877d96f4efSBrian Somers 					dst_addr = addr;
7887d96f4efSBrian Somers 					dst_mask = mask;
7897d96f4efSBrian Somers 				}
7907d96f4efSBrian Somers 			}
7917d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7927d96f4efSBrian Somers 			break;
7937d96f4efSBrian Somers 
7947d96f4efSBrian Somers 		default:
795ccd57eeaSPaolo Pisati 			ret = -1;
796ccd57eeaSPaolo Pisati 			goto getout;
7977d96f4efSBrian Somers 			break;
7987d96f4efSBrian Somers 		}
7997d96f4efSBrian Somers 
800d9e630b5SAndrey A. Chernov 		do {
801d9e630b5SAndrey A. Chernov 			token = strsep(&res, " \t");
802d9e630b5SAndrey A. Chernov 		} while (token != NULL && !*token);
8037d96f4efSBrian Somers 	}
8047d96f4efSBrian Somers #undef STATE_READ_KEYWORD
8057d96f4efSBrian Somers #undef STATE_READ_TYPE
8067d96f4efSBrian Somers #undef STATE_READ_PORT
8077d96f4efSBrian Somers #undef STATE_READ_SERVER
8087d96f4efSBrian Somers #undef STATE_READ_RULE
8097d96f4efSBrian Somers #undef STATE_READ_DELETE
8107d96f4efSBrian Somers #undef STATE_READ_PROTO
8117d96f4efSBrian Somers #undef STATE_READ_SRC
8127d96f4efSBrian Somers #undef STATE_READ_DST
8137d96f4efSBrian Somers 
8147d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
8157d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
8167d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
8177d96f4efSBrian Somers 
818f0f93429SDag-Erling Smørgrav 	if (strlen(str_port) != 0) {
8197d96f4efSBrian Somers 		int err;
8207d96f4efSBrian Somers 
8217d96f4efSBrian Somers 		err = IpPort(str_port, proto, &proxy_port);
822ccd57eeaSPaolo Pisati 		if (err) {
823ccd57eeaSPaolo Pisati 			ret = -1;
824ccd57eeaSPaolo Pisati 			goto getout;
825ccd57eeaSPaolo Pisati 		}
826f0f93429SDag-Erling Smørgrav 	} else {
8277d96f4efSBrian Somers 		proxy_port = 0;
8287d96f4efSBrian Somers 	}
8297d96f4efSBrian Somers 
830f0f93429SDag-Erling Smørgrav 	if (strlen(str_server_port) != 0) {
8317d96f4efSBrian Somers 		int err;
8327d96f4efSBrian Somers 
8337d96f4efSBrian Somers 		err = IpPort(str_server_port, proto, &server_port);
834ccd57eeaSPaolo Pisati 		if (err) {
835ccd57eeaSPaolo Pisati 			ret = -1;
836ccd57eeaSPaolo Pisati 			goto getout;
837ccd57eeaSPaolo Pisati 		}
838f0f93429SDag-Erling Smørgrav 	} else {
8397d96f4efSBrian Somers 		server_port = 0;
8407d96f4efSBrian Somers 	}
8417d96f4efSBrian Somers 
8427d96f4efSBrian Somers /* Check that at least the server address has been defined */
843ccd57eeaSPaolo Pisati 	if (server_addr.s_addr == 0) {
844ccd57eeaSPaolo Pisati 		ret = -1;
845ccd57eeaSPaolo Pisati 		goto getout;
846ccd57eeaSPaolo Pisati 	}
8477d96f4efSBrian Somers 
8487d96f4efSBrian Somers /* Add to linked list */
8497d96f4efSBrian Somers 	proxy_entry = malloc(sizeof(struct proxy_entry));
850ccd57eeaSPaolo Pisati 	if (proxy_entry == NULL) {
851ccd57eeaSPaolo Pisati 		ret = -1;
852ccd57eeaSPaolo Pisati 		goto getout;
853ccd57eeaSPaolo Pisati 	}
8547d96f4efSBrian Somers 
8557d96f4efSBrian Somers 	proxy_entry->proxy_type = proxy_type;
8567d96f4efSBrian Somers 	proxy_entry->rule_index = rule_index;
8577d96f4efSBrian Somers 	proxy_entry->proto = proto;
8587d96f4efSBrian Somers 	proxy_entry->proxy_port = htons(proxy_port);
8597d96f4efSBrian Somers 	proxy_entry->server_port = htons(server_port);
8607d96f4efSBrian Somers 	proxy_entry->server_addr = server_addr;
8617d96f4efSBrian Somers 	proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
8627d96f4efSBrian Somers 	proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
8637d96f4efSBrian Somers 	proxy_entry->src_mask = src_mask;
8647d96f4efSBrian Somers 	proxy_entry->dst_mask = dst_mask;
8657d96f4efSBrian Somers 
8665e289f9eSPoul-Henning Kamp 	RuleAdd(la, proxy_entry);
8677d96f4efSBrian Somers 
868ccd57eeaSPaolo Pisati getout:
869ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
870ccd57eeaSPaolo Pisati 	return (ret);
8717d96f4efSBrian Somers }
872